updated authentication scheme
added middleware
This commit is contained in:
parent
7b7bd3f4f0
commit
23314af0d0
10 changed files with 182 additions and 106 deletions
8
app.js
8
app.js
|
|
@ -5,7 +5,9 @@ const mongoose = require("mongoose");
|
|||
const cookieParser = require("cookie-parser");
|
||||
require("dotenv").config();
|
||||
|
||||
const router = require("./routes.js");
|
||||
const indexRouter = require("./routes/index.js");
|
||||
const postRouter = require("./routes/post.js");
|
||||
const userRouter = require("./routes/user.js");
|
||||
|
||||
const app = express();
|
||||
|
||||
|
|
@ -38,6 +40,8 @@ app.use(express.static(path.join(__dirname, "public")));
|
|||
app.use(cors());
|
||||
|
||||
// routing
|
||||
app.use("/", router);
|
||||
app.use("/", indexRouter);
|
||||
app.use("/post", postRouter);
|
||||
app.use("/user", userRouter);
|
||||
|
||||
module.exports = app;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,39 @@
|
|||
const { default: mongoose } = require("mongoose");
|
||||
const asyncHandler = require("express-async-handler");
|
||||
const { body, validationResult } = require("express-validator");
|
||||
const jwt = require("jsonwebtoken");
|
||||
|
||||
const Post = require("../models/post.js");
|
||||
const Comment = require("../models/comment.js");
|
||||
const hasToken = require("../middleware/hasToken.js");
|
||||
const sameAuthor = require("../middleware/sameAuthor.js");
|
||||
|
||||
// returns json object with ALL posts and comments
|
||||
exports.index = asyncHandler(async (req, res, next) => {
|
||||
const dbPosts = await Post.find().lean().exec();
|
||||
// get all posts
|
||||
const dbPosts = await Post.find({ published: true }).lean().exec();
|
||||
// check for authorization
|
||||
const token = req.cookies.JWT_TOKEN;
|
||||
blocc: if (token) {
|
||||
try {
|
||||
jwt.verify(token, process.env.SECRET_KEY);
|
||||
} catch {
|
||||
break blocc;
|
||||
}
|
||||
// run through unpublished posts
|
||||
const unpublished = await Post.find({ published: false }).lean().exec();
|
||||
for (let z = 0; z < unpublished.length; z++) {
|
||||
const post = unpublished[i];
|
||||
const author = post.author;
|
||||
let opts = {
|
||||
expiresIn: "1d",
|
||||
};
|
||||
const authorToken = jwt.sign({ author }, process.env.SECRET_KEY, opts);
|
||||
// if any are by the current user, append to dbPosts
|
||||
if (token == authorToken) {
|
||||
dbPosts.push(post);
|
||||
}
|
||||
}
|
||||
}
|
||||
const posts = [];
|
||||
for (let i = 0; i < dbPosts.length; i++) {
|
||||
const comments = await Comment.find({ post: dbPosts[i]._id });
|
||||
|
|
@ -16,7 +42,6 @@ exports.index = asyncHandler(async (req, res, next) => {
|
|||
date: dbPosts[i].date,
|
||||
text: dbPosts[i].text,
|
||||
author: dbPosts[i].author,
|
||||
published: dbPosts[i].published,
|
||||
_id: dbPosts[i]._id,
|
||||
comments: comments,
|
||||
};
|
||||
|
|
@ -40,14 +65,6 @@ exports.post = [
|
|||
.escape(),
|
||||
|
||||
asyncHandler(async (req, res, next) => {
|
||||
// begin by authorizing token
|
||||
const token = req.cookies.JWT_TOKEN;
|
||||
if (!token) {
|
||||
return res.status(403).json({
|
||||
message: "Not authorized!",
|
||||
});
|
||||
}
|
||||
|
||||
// then return any validation errors
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
|
|
@ -77,7 +94,14 @@ exports.post = [
|
|||
|
||||
// returns post in json format - R
|
||||
exports.get = asyncHandler(async (req, res, next) => {
|
||||
const post = await Post.findOne({ _id: req.params.postID }).lean().exec();
|
||||
const post = await Post.findById(req.params.postID).lean().exec();
|
||||
// if post is not published, not publicly visible
|
||||
if (!post.published) {
|
||||
hasToken();
|
||||
sameAuthor();
|
||||
return res.status(200).json({ post });
|
||||
}
|
||||
// otherwise return post if published
|
||||
return res.status(200).json({ post });
|
||||
});
|
||||
|
||||
|
|
@ -97,15 +121,7 @@ exports.put = [
|
|||
|
||||
// Process request after sanitization and validation
|
||||
asyncHandler(async (req, res, next) => {
|
||||
// begin by authorizing token
|
||||
const token = req.cookies.JWT_TOKEN;
|
||||
if (!token) {
|
||||
return res.status(403).json({
|
||||
message: "Not authorized!",
|
||||
});
|
||||
}
|
||||
|
||||
// then return any validation errors
|
||||
// return any validation errors
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
return res.status(400).json({
|
||||
|
|
@ -115,13 +131,13 @@ exports.put = [
|
|||
}
|
||||
|
||||
// else data is valid, update post object
|
||||
const dbPost = await Post.findOne({ _id: req.params.postID }).lean().exec();
|
||||
const dbPost = await Post.findById(req.params.postID).lean().exec();
|
||||
const post = new Post({
|
||||
title: req.body.title,
|
||||
date: new Date(),
|
||||
text: req.body.text,
|
||||
author: dbPost.author,
|
||||
published: dbPost.published,
|
||||
published: req.body.published,
|
||||
_id: dbPost._id,
|
||||
});
|
||||
|
||||
|
|
@ -136,12 +152,6 @@ exports.put = [
|
|||
|
||||
// deletes a post - D
|
||||
exports.delete = asyncHandler(async (req, res, next) => {
|
||||
const token = req.cookies.JWT_TOKEN;
|
||||
if (!token) {
|
||||
return res.status(403).json({
|
||||
message: "Not authorized!",
|
||||
});
|
||||
}
|
||||
await Post.findByIdAndDelete({ _id: req.params.postID }).exec();
|
||||
await Post.findByIdAndDelete(req.params.postID).exec();
|
||||
return res.status(200).json({ message: "Post deleted!" });
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
const asyncHandler = require("express-async-handler");
|
||||
const bcrypt = require("bcryptjs");
|
||||
const User = require("../models/user.js");
|
||||
const jwt = require("jsonwebtoken");
|
||||
const { body, validationResult } = require("express-validator");
|
||||
const { default: mongoose } = require("mongoose");
|
||||
|
||||
|
|
@ -60,7 +59,7 @@ exports.get = asyncHandler(async (req, res, next) => {
|
|||
.lean()
|
||||
.exec(); // gets user based on username
|
||||
return res.status(200).json({
|
||||
user: user,
|
||||
user,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -81,11 +80,6 @@ exports.post = [
|
|||
asyncHandler(async (req, res, next) => {
|
||||
// begin by authorizing token
|
||||
const token = req.cookies.JWT_TOKEN;
|
||||
if (!token) {
|
||||
return res.status(403).json({
|
||||
message: "Not authorized!",
|
||||
});
|
||||
}
|
||||
// if token is not for this user - compares by creating another token
|
||||
let opts = {
|
||||
expiresIn: "1d",
|
||||
|
|
@ -137,29 +131,6 @@ exports.post = [
|
|||
|
||||
// D
|
||||
exports.delete = asyncHandler(async (req, res, next) => {
|
||||
// begin by authorizing token
|
||||
const token = req.cookies.JWT_TOKEN;
|
||||
if (!token) {
|
||||
return res.status(403).json({
|
||||
message: "Not authorized!",
|
||||
});
|
||||
}
|
||||
// if token is not for this user - compares by creating another token
|
||||
let opts = {
|
||||
expiresIn: "1d",
|
||||
};
|
||||
const originalUsername = req.params.username;
|
||||
const userToken = jwt.sign(
|
||||
{ originalUsername },
|
||||
process.env.SECRET_KEY,
|
||||
opts
|
||||
);
|
||||
if (token != userToken) {
|
||||
return res.status(403).json({
|
||||
message: "Not authorized!",
|
||||
});
|
||||
}
|
||||
|
||||
// if everything is correct, delete user
|
||||
await User.findOneAndDelete({ username: originalUsername }).exec();
|
||||
return res.status(200).json({ message: "Post deleted!" });
|
||||
|
|
|
|||
22
middleware/hasToken.js
Normal file
22
middleware/hasToken.js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
const hasToken = (req, res, next) => {
|
||||
// get token
|
||||
const token = req.cookies.JWT_TOKEN;
|
||||
if (!token) {
|
||||
// if none, error
|
||||
return res.status(403).json({
|
||||
message: "Not authorized!",
|
||||
});
|
||||
}
|
||||
try {
|
||||
jwt.verify(token, process.env.SECRET_KEY);
|
||||
// move forward
|
||||
return next();
|
||||
} catch {
|
||||
// if incorrect, error
|
||||
return res.status(403).json({
|
||||
message: "Not authorized!",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = hasToken;
|
||||
26
middleware/sameAuthor.js
Normal file
26
middleware/sameAuthor.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
const jwt = require("jsonwebtoken");
|
||||
const asyncHandler = require("express-async-handler");
|
||||
const { default: mongoose } = require("mongoose");
|
||||
const Post = require("../models/post.js");
|
||||
|
||||
const sameAuthor = asyncHandler(async (req, res, next) => {
|
||||
// get token
|
||||
const token = req.cookies.JWT_TOKEN;
|
||||
// make token with identical user information
|
||||
let opts = {
|
||||
expiresIn: "1d",
|
||||
};
|
||||
const post = await Post.findById(req.params.postID).lean().exec();
|
||||
const author = post.author;
|
||||
const userToken = jwt.sign({ author }, process.env.SECRET_KEY, opts);
|
||||
// compare the two, if the token does not match then the action is unauthorized
|
||||
if (token != userToken) {
|
||||
return res.status(403).json({
|
||||
message: "Not authorized!",
|
||||
});
|
||||
}
|
||||
// otherwise all good
|
||||
return next();
|
||||
});
|
||||
|
||||
module.exports = sameAuthor;
|
||||
22
middleware/sameUser.js
Normal file
22
middleware/sameUser.js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
const jwt = require("jsonwebtoken");
|
||||
|
||||
const sameUser = (req, res, next) => {
|
||||
// get token
|
||||
const token = req.cookies.JWT_TOKEN;
|
||||
// make token with identical user information
|
||||
let opts = {
|
||||
expiresIn: "1d",
|
||||
};
|
||||
const username = req.params.username;
|
||||
const userToken = jwt.sign({ username }, process.env.SECRET_KEY, opts);
|
||||
// compare the two, if the token does not match then the action is unauthorized
|
||||
if (token != userToken) {
|
||||
return res.status(403).json({
|
||||
message: "Not authorized!",
|
||||
});
|
||||
}
|
||||
// otherwise all good
|
||||
return next();
|
||||
};
|
||||
|
||||
module.exports = sameUser;
|
||||
44
routes.js
44
routes.js
|
|
@ -1,44 +0,0 @@
|
|||
const express = require("express");
|
||||
const router = express.Router();
|
||||
const login_controller = require("./controllers/login.js");
|
||||
const post_controller = require("./controllers/post.js");
|
||||
const comment_controller = require("./controllers/comment.js");
|
||||
const user_controller = require("./controllers/user.js");
|
||||
|
||||
// list all posts and append comments to each post based on id, return as json
|
||||
router.get("/", post_controller.index);
|
||||
|
||||
// login page
|
||||
router.post("/login", login_controller.post);
|
||||
|
||||
// user get
|
||||
router.get("/:username", user_controller.get);
|
||||
|
||||
// user post
|
||||
router.post("/new_user", user_controller.post);
|
||||
|
||||
// user put
|
||||
router.put("/:username", user_controller.put);
|
||||
|
||||
// user delete
|
||||
router.delete("/:username", user_controller.delete);
|
||||
|
||||
// post post
|
||||
router.post("/new_post", post_controller.post);
|
||||
|
||||
// post get
|
||||
router.get("/:postID", post_controller.get);
|
||||
|
||||
// post put
|
||||
router.put("/:postID", post_controller.put);
|
||||
|
||||
// post delete
|
||||
router.delete("/:postID", post_controller.delete);
|
||||
|
||||
// comment post
|
||||
router.post("/:postID/new_comment", comment_controller.post);
|
||||
|
||||
// comment get
|
||||
router.get("/:postID/:commentID", comment_controller.get);
|
||||
|
||||
module.exports = router;
|
||||
18
routes/index.js
Normal file
18
routes/index.js
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
const express = require("express");
|
||||
const router = express.Router();
|
||||
const login_controller = require("../controllers/login.js");
|
||||
const post_controller = require("../controllers/post.js");
|
||||
const hasToken = require("../middleware/hasToken.js");
|
||||
|
||||
// list all posts and append comments to each post based on id, return as json
|
||||
router.get("/", post_controller.index);
|
||||
|
||||
// login page
|
||||
router.post("/login", login_controller.post);
|
||||
|
||||
// authentication checking page - used by frontend
|
||||
router.get("/ping", hasToken, (req, res) => {
|
||||
return res.status(200).json({ message: "Authenticated!" });
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
26
routes/post.js
Normal file
26
routes/post.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
const express = require("express");
|
||||
const router = express.Router();
|
||||
const post_controller = require("../controllers/post.js");
|
||||
const comment_controller = require("../controllers/comment.js");
|
||||
const hasToken = require("../middleware/hasToken.js");
|
||||
const sameAuthor = require("../middleware/sameAuthor.js");
|
||||
|
||||
// post post
|
||||
router.post("/new_post", hasToken, post_controller.post);
|
||||
|
||||
// post get
|
||||
router.get("/:postID", post_controller.get);
|
||||
|
||||
// post put
|
||||
router.put("/:postID", hasToken, sameAuthor, post_controller.put);
|
||||
|
||||
// post delete
|
||||
router.delete("/:postID", hasToken, sameAuthor, post_controller.delete);
|
||||
|
||||
// comment post
|
||||
router.post("/:postID/new_comment", comment_controller.post);
|
||||
|
||||
// comment get
|
||||
router.get("/:postID/:commentID", comment_controller.get);
|
||||
|
||||
module.exports = router;
|
||||
21
routes/user.js
Normal file
21
routes/user.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
const express = require("express");
|
||||
const router = express.Router();
|
||||
const user_controller = require("../controllers/user.js");
|
||||
const hasToken = require("../middleware/hasToken.js");
|
||||
const sameUser = require("../middleware/sameUser.js");
|
||||
|
||||
// hardcoded URLs always go before matchers
|
||||
|
||||
// user post
|
||||
router.post("/new_user", user_controller.post);
|
||||
|
||||
// user get
|
||||
router.get("/:username", hasToken, user_controller.get);
|
||||
|
||||
// user put
|
||||
router.put("/:username", hasToken, sameUser, user_controller.put);
|
||||
|
||||
// user delete
|
||||
router.delete("/:username", hasToken, sameUser, user_controller.delete);
|
||||
|
||||
module.exports = router;
|
||||
Loading…
Add table
Reference in a new issue