Post authorization doesn't work - express

I'm trying to restrict ability for one user to edit someone else's posts.
When I click 'Edit post' it change the author of the post, is it because of 'save' method or ?
Here is my attempt:
router.put('/posts/:id', passport.authenticate('jwt'), (req, res) => {
Post.findOne({_id: req.params.id}, (err, post) => {
if (err) throw err;
if (post.author = req.user._id) {
post.title = req.body.title,
post.content = req.body.content,
post.postImageUrl = req.body.postImageUrl
post.save((err, updatedPost) => {
if (err) throw err;
else {
res.json({message:'You have successfully updated your post', success: true});
}
});
} else {
res.json({success: false, message: 'You are not allowed to do this.'});
}
});
});
I checked post.author and req.user._id, they match.

Please check your condition for checking if the current user is the post's author.Instead of checking for equality you are trying to assign and change the author value.
if (post.author = req.user._id)
Solution:
Mongoose offers a .equals method for checking equality for object ids.Here is the link for the docs for mongodb-native driver .equals method, which is used by Mongoose.
if (post.author.equals(req.user._id))

Related

Callback function 'next' is executed automatically without making a call to it

I have this POST method which uses FetchURL middleware to fetch data from the url submitted by the user.
router.post('/', FetchURL, (req, res) => {
console.info('data received');
...
})
Everything works with response.ok being true, but the contrary case doesn't quite work as expected.
I don't want next to be called when response.ok equals false.
But I get to see "data received" logged to the console which means the next function does get called on its own.
fetch_url.js
function FetchURL(req, res, next) {
fetch(req.body.input_url)
.then(response => {
if(response.ok)
return response.json();
// else render error message on the client machine
res.status(response.status)
.render('index', {
errStatus: [response.status, response.statusText]
});
/* Throwing an Error here is the only way I could prevent the next callback */
// throw new Error(`Request failed with status code ${response.status}.`);
})
.then(data => {
req.data = data;
next();
})
.catch(err => console.error(err));
}
I could not find anything relevant on the documentation of expressjs middleware. The only way I could prevent next from being called is by throwing an Error on the server.
What happens behind the scene here?
try making a second check before next is called like following
function FetchURL(req, res, next) {
fetch(req.body.input_url)
.then(response => {
if(response.ok) // wrap your response in a temporary object.
return { fail: false, data: response.json() } ;
// else render error message on the client machine
res.status(response.status)
.render('index', {
errStatus: [response.status, response.statusText]
});
/* Instead of throwing an Error, return something indicating error */
return { fail: true };
})
.then(data => {
// check if previous procedure has failed.
if(!data.fail) {
req.data = data.data;
next();
}
})
.catch(err => console.error(err));
}

Express Returning After next()

came from Java. Was messing around with ExpressJS, I return out of a function after sending a next() if I dont add the return, then code after the next() function still executes when next() is invoked, currently it works, return escapes this behaviour, but I was wondering if this is correct way to do this, or am I developing bad habbits. Nothing is really after the next() in terms of code sequence.
function('/login', (req,res, next) => {
User.findOne({
email: username
}, (err, user) => {
if (user) {
var validPassword = user.comparePassword(password);
if (validPassword) {
let token = Helpers.getJwt(user);
res.send({
success: true,
message: 'Successful Login',
token: token
})
} else {
next(
Boom.badRequest('Invalid Credentials.', {
success: false,
message: 'Credentials did not match our records.'
}));
return;
}
} else {
next(
Boom.badRequest('User not found.', {
success: false,
message: 'User was not found, please register.'
}));
return;
}
});
EDIT: I have middleware called with the next(), my error middleware.
First, You aren't next-ing to anything here(pun intended).
You call middleware:next() function if there is another middleware:function within the chain of a particular route or a group of routes app.use(middleware:function).
Example:
app.get('/user/:id', function (req, res, next) {
console.log('ID:', req.params.id)
next()
}, function (req, res, next) {
res.send('User Info')
})
I'd advice you read on Express Middlewares.
so yeah, you want to check if the user is valid before proceeding with the request.
Below code is just to explain how middle-ware works:
The idea is that, one middleware:function process the request and passes control down to the next function within the chain.
I'm assuming your Boom.badRequest just generates a json payload e.g {};
So this is probably an elegant way to achieve what you want, but im not sure doing this for login is ideal, maybe better for checking if a user's token is valid.
app.post('/login', /*MiddleWare Function*/(req, res, next) => {
User.findOne({email: username}, (err, user) => {
if (user) {
const validPassword = user.comparePassword(req.body.password);
if (!validPassword) return res.status(401).send(Boom.badRequest('User not found.', {
success: false,
message: 'User was not found, please register.'
}));
req.token = Helpers.getJwt(user);
next();// it will move execution to the next function we have below
} else {
res.status(401).send(Boom.badRequest('User not found.', {
success: false,
message: 'User was not found, please register.'
}));
//no need to next here.
}
})
}, /*OUR NEXT FUNCTION*/(req, res) => {
res.send({
success: true,
message: 'Successful Login',
token: req.token//notice that our token can be retrieved here
})
});
So in general, you might just want to have a middleware:function that is called first on a group of specific routes.
app.use(['/users*', '/logout'], (req, res, next) => {
/*
* What this means is that for every request that maps to /users
* or /logout this middleware:function will be called first.
*/
//we can check|test if this visitor has valid credentials.
next();//passes control to app.get('/users/whatEverItIS?') or app.post('/logout');
});
app.post('/users/whatEverItIs', (req, res)=>{
res.send("I passed the middleware test that is why im called");
});
That return statement is unnecessary. Firstly due to the fact that you are not returning anything and secondly because you are passing control to your next middleware using next method, thus that return is useless there and will be returning undefined.

PUT request only occurs on second attempt

I have an express route that changes a Post's "checked" value to it's opposite boolean value (true => false, false => true). For some reason, the API return the opposite of what is in the DB. If I do a GET request after a PUT request, I get the opposite boolean value of what the PUT route gives me, which is accurate to the state of the DB.
Here is the route. Anyone see what's going on here?
app.put('/posts/:id', jsonParser, (req, res) => {
let id = req.params.id;
Post.findById( id )
.then(post => {
if(!post) {
return res.status(404).json({ message: 'Post not found' });
}
return Post.findByIdAndUpdate(id, { "checked": !post.checked })
})
.then(result => {
return res.status(202).json(result.apiRepr())
})
.catch(err => {
if(err) {
return res.status(500).json({ message: "There was a problem"})
}
});
});
It appears the .findByIdAndUpdate part IS updating the DB, but then the object below that gets returned is still the old data.
By default findByIdAndUpdate return the original document, you have to set the new option to true in order to get the modified document rather than the original:
return Post.findByIdAndUpdate(id, { "checked": !post.checked }, { new: true }) ...
findByIdAndUpdate Api doc

PUT inside a POST request in expressJS

after searching and trying a lot of different things, I find myself in front of this problem : I want to post a content and save the id to an object that belongs in another schema, I'm using mongoose.
Project.findByid is finding the good project and if I log project after modification, the item is as I want it but the save part just doesn't work.
My question is : Is it possible to do a PUT action inside of a POST request, I tried to remove the first .save and it's not working either.
app.post('/pages', (req, res) => {
var db = req.db;
var name = req.body.name;
var parent = req.body.parent;
var myId = mongoose.Types.ObjectId();
var new_content = new Content({
name: name,
_id: myId,
})
new_content.save(function (error, item) {
if (error) {console.log(error)}
})
Project.findById(parent, 'content', function (error, project) {
if (error) { console.error(error); }
project.content[name] = myId;
project.save(function (error) {
if (error) {
console.log(error)
}
res.send({
success: true
})
})
})
})
Simply use
app.all(path, callback [, callback ...])
Instead of
app.post
More info here ExpressJS Docs

Express REST API - Delete Method

I am getting stuck on the delete method for my API. My application requires a user to log in and then he can add courses. The courses are stored in a nested array inside the User model. I want the user to be able to cancel (delete) a course from the view and then have the course deleted from the user's profile on the server. I am getting a 404 response event though the variables I am comparing are identical.
This is my ajax call to delete a specific course:
jQuery.ajax({
url: "/test/signups/5387c1a0fb06e48f4658170c",
type: "DELETE",
success: function (data, textStatus, jqXHR) {
console.log("Post resposne:");
console.dir(data);
console.log(textStatus);
console.dir(jqXHR);
}
});
This is my delete method:
app.delete('/test/signups/:id', isLoggedIn, function(req, res) {
User.findOne({'_id': req.user.id }, function(err, user) {
if (err)
return done(err);
if (user) {
var found = false;
var singlesignup = user.signup.filter(function(e){ return e._id == req.params.id })[0]
user.signup.forEach(function (singlesignup, index) {
if (singlesignup._id === req.params.id) {
found = index;
}
});
if(found) {
user.signup.splice(found, 1);
res.json(200, {status: 'deleted'});
} else {
res.json(404, {status: 'invalid survey question deletion'});
}
}
});
});
The _id values in mongodb are not strings, they are instances of the ObjectId class and they don't work correctly with the == or === operators. It's completely a nuisance. But anyway try converting them to strings before comparing: singlesignup._id.toString() === req.params.id. To get it truly correct in the long run, make sure you handle all the cases of null, string or ObjectId. Consider a helper library such as objectid.