What request status should I apply on wrong client applies? - node.js

I'm trying to apply request status to my file.
For now, I have 3 ifs. Can you tell me what status to add to each one of them and why?
for example: first one res.status(400).render....
exports.register = (req, res) => {
// Get the POST data
const { firstName, lastName, email, password, passwordConfirm } = req.body;
// Check if everything is filled.
if (firstName === '' || lastName === '' || email === '' || password === '' || passwordConfirm === '' ) {
return res.render('register', {
message: 'One of the fields is missing. Please try again.'
});
} else {
db.query('SELECT * FROM user WHERE email = ?', [email], (error, results) => {
// Check if email already exists
if (results.length > 0) {
return res.render('register', {
message: 'The email address is already exists. Please try a different one.'
});
// Check if passwords match
} else if (password !== passwordConfirm) {
return res.render('register', {
message: 'Passwords do not match. Please try again.'
});
}
});
}
};

When a field is missing, the client clearly made a bad request, so status 400 (Bad Request) would be appropriate there. (Though, ideally, this validation would be done on the client-side too, and prevent users who haven't tampered with the client code from making such a request to the server in the first place)
If the submitted email address conflicts, 401 Unauthorized is an option - it indicates that if the user re-submits with non-conflicting credentials, the request will go through successfully, and that there was nothing inherently wrong with the request other than the fact that it didn't pass a requirement that only the server could determine.
Status 400 is also appropriate if the passwords don't match - and like when a field is missing, that is validation that should also be done on the client-side, so that such requests don't make it to the server in the first place under normal circumstances (and if a request does make it to the server, it's a badly formatted request, hence 400).
But, keep in mind that status codes only really matter for how your client-side code deals with them. As long as you know what sorts of statuses and messages your server can reply with, and write your client accordingly, you can still make a working app, without having to care a lot about the precisely applicable semantics of HTTP status codes.

Related

I want to authenticate my comment section of my blog in node js

I have my comment section below a post. The only thing I want to know that how to authenticate the comment page.
For example, in reddit unless you login you won't be able to comment right? so how to make that? what steps should I follow? And yeah I know how to authenticate, I am using passport js for authentication. I am able to block contents of my page and all that stuff but only having problem with the comment part.
Upon receiving request to fetch the post and the comments related to it, check to see if the user has sent the token in request headers. you can use simple if-else block to this. if you are using sessions, check to see if the user has an active session. So if these conditions are met, query comment documents and return them in response, else just return the post.
in frontend if the response received from server does not have comments, are comments are null (it really depends on how you send the response) then just show a message saying that User must sign in
Edit 1
in express in request object there are headers and you can send token in these headers and access it like this:
request.headers['your-token-name']
after that you have the validate the token and grant or refuse access to contents.
Now suppose the access is granted and decoded, token is saved in request object for example in variable named decoded. Now
route.get('/:postId?', async(req, res, next)=>{
//place the validate you postId format
try {
const post = await Posts.findOne({postId:req.params.postId})
if(!post)
return res.json({success:false, message:'Post not found'})
if(req.decoded !== undefined || req.decoded !== null){
const comments = await Comments.find({/*Your condition*/ })
return res.json({success:true, comments: comments, post:post})
}else{
return res.json({success:true, message:'Login to view the comments', post:post})
}
} catch (error) {
next(error)
}})
This is very simple code to just get simple idea of how it works in express backend. Now you also have to write a middleware to validate token.
In this case if token is sent then validate it. if it is valid grant access else return access denied. Something like this
App.use(async (Request,Response,Next)=>{
try {
let sentToken = Request.headers['access-token'];
if(sentToken !== undefined && sentToken !== null){
Request.decoded = await verify(sentToken,'your secret key');
if(!isTokenValid(Request.decoded))
return Response.status(403).send({success:false, message:'Please Sign Up or login to continue'});
}
await Next();
} catch (error) {
return Next(error);
}});

How do I get the updated document back after I call document.save() function in mongoose?

I'm trying to create a settings page where the user can update their credentials (Username and such)
The length of the username is 5 < length < 30. Therefore, if the user enters a username that doesn't follow these rules the inbuilt validation kicks in and prevents the user from saving these credentials. Following this, I also update their JWT Token so that the changes get reflected in the dashboard.
server code (node.js)
/* ................
code to update other fields
...............*/
if (newUsername && newUsername !== user.username) {
user.username = newUsername;
messages.push({
message: 'Username updated successfuly',
error: false,
});
}
await user.save({ j: true }, (err) => {
if (err) {
messages.push({ message: err.message, error: true });
}
res.clearCookie(accessTokenName);
createJWTCookie(user, res);
res.render('settings', { messages });
});
However, this doesn't work like I want it to. The inbuilt validation does kick in and prevents saving of invalid fields but the token still gets updated with wrong info. I believe this is because the (user) argument of createJWTCookie still has information from before the user.save() method was run.
Even if I console.log(user) after the user.save() method has been run it contains the invalid input from the user. But if I logout and login again (This creates a new JWT Cookie with the user from the database), the token that is generated only has valid fields. This means that only valid fields were updated while the other changes were discarded.
How do I get the updated user document after user.save() has been run so I can create a valid JWT cookie without the user having to logout and login again?
Calling user.save() doesn't make any changes to your user object, it just updates the document on your database. If the inbuilt validation kicks in due to an invalid username, it will prevent the save() from happening (which is good to have as a fail-safe), but won't affect the actual user object in your code.
To solve this, you would need to write in your own validation when updating the user object. This should work:
if (newUsername && newUsername !== user.username && newUsername.length > 5 && newUserName.length < 30) {
user.username = newUsername;
messages.push({
message: 'Username updated successfuly',
error: false,
});
}

Failing to get a response back from a web api call in node

this particular Node issue has been driving me crazy for going on a week.
I have to create a layer of friction (a modal that asks the user if they're sure) in the process of a csv file upload. Essentially, the flow will be:
User Clicks 'UPLOAD SPREAD SHEET' > File uploads to s3 > S3 returns a reference key > Pass reference key into micro service web api to evaluate > if true => ask user 'if they're sure' > If user is sure continue uploading > pass reference key onward to another endpoint, same service, to finish the upload. false return would continue on to the upload with no modal.
its kind of a silly product-based functionality that makes a show of alerting the user to potential duplicate entries in their spreadsheet since we can't currently detect duplicate entries ourselves.
Problem is, I can't get a response to return from the evaluation to save my life. If I console.log the response, I can see it in Node's terminal window but nothing comes back in the network tab for the response. I'm not sure if it's because it's a file upload, if it's busyboy, if it's just not the right syntax for the response type but endless googling has brought me no answers and I'd love it if someone more experienced with Node and Express could take a look.
router.post('/import/csv',
// a bunch of aws s3 stuff to upload the file and return the key
s3.upload(uploadParams, (err, data) => {
if (err) {
res.status(500).send({
error_message: 'Unable to upload csv. Please try again.',
error_data: err
});
} else if (data) {
// creating the key object to pass in
const defaultImportCheck = {
body: data.Key
};
// endpoint that will evaluate the s3 reference key
SvcWebApiClient.guestGroup.defaultImportCheck(defaultImportCheck)
.then((response) => {
if (response.status === 'success') {
// where the response should be. this works but doesn't actually send anything.
res.send(response);
} else {
const errorJson = {
message: response.message,
category: response.category,
trigger: response.trigger,
errors: response.errors
};
res.status(500).send(errorJson);
}
})
.catch((error) => {
res.status(500).send({
error_message: 'Unable to upload csv. Please try again.',
error_data: error
});
});
}
});
});
req.pipe(busboy);
}
);
Got it, for anyone that ends up having my kind of problem. It's a two parter so buckle up.
1) the action function that handles the response on the react side didn't convert the response into json. Apparently, what would get returned is a "readable stream" which should have then converted to json. it didn't.
2) the response itself needed to be in json as well.
so from the action function:
export function csvUpload(file) {
do some stuff
return fetch(fetch some stuff) { with some parameters }
.then(some error stuff)
.then(response => response.response.json())
}
then from the post request:
if (response.status === "success") {
res.json({ valid: response.data, token: data.Key)};
}
this returns an object with what I need back to the client. hope this helps someone else.

Node.JS Rethink-DB check if username and email is already exist

I working on a login/register system with Node based on the RethinkDB Chat example when I found that it doesn't check if the user exists with email or username something that's a problem.
When I was looking to solve this I was not able to find out why because of running a database check would require a callback with a function something that makes it really hard to achieve.
if (typeof req.user !== 'undefined') {
res.redirect('/account');
return;
}
if (!validateEmail(req.param('email'))) {
req.flash('error', 'Not a valid email address!')
res.redirect('/register');
return;
}
// Add a check for EMAIL/USERNAME here.
if (req.param('password') !== req.param('password2')) {
req.flash('error', 'Passwords does not match!')
res.redirect('/register');
return;
}
What I need help with it to if a user exists with a username or mail that's equal with the one in the form it will send a:
if (alreadyExists) {
req.flash('error', 'That username/email is already in use.')
res.redirect('/register');
return;
}
So the main problem is I have to get to know if it exists in the same functions as the other ones and not in a callback. Any help is appreciated!
The way I usually handle something like this is :
User.filter({username:req.body.username}).run().then(function(userArray){
if(userArray[0]){return res.status(500).json({Error : "Username is in use"});}
I have not run into any issues here using a callback. Is there a specific reason you were trying to avoid it?
Edit : Obviously, replace username in my example with whatever you want to check for, in your case email address. And User here is my user model. I also agree with Tholle about using a POST request. You never want to send user's information/credentials in the query string/URL
To check if a user with the given email address exists, you will have to do a check in your RethinkDB-database, which is asynchronous. This can not be achieved without a callback, but it's not that bad!
var r = require('rethinkdbdash')();
function getUserByEmailAddress(emailAddress) {
return r.db('test').table('user')
.getAll(emailAddress, {index: 'emailAddress'}).run();
}
app.post('/register', function(req, res) {
// User already has a session. Not allowed to log in.
if(req.user) {
return res.redirect('/account');
} else if(!validateEmail(req.body.emailAddress)) {
return res.status(500).send('Not a valid email address');
} else if(req.body.password !== req.body.password2) {
return res.status(500).send('Passwords do not match');
}
getUserByEmailAddress(req.body.emailAddress).then(function(user) {
if(user) {
res.status(500).send('User with given email address already exists');
} else {
// New email address! Encrypt password, add to db, etc.
}
})
}
Note that you will have to create a secondary index for this.
You should probably also consider posting the form with a POST-request instead of a GET-request.

Redis and NodeJs - Can't auth a user

Ok, I give up.
I've tried many things to create a simple login form. The form itself renders fine, it's just the processing of the POST datas which is wrong :-)
I have a Redis database with some keys in it. Firstly, there is a users set with a list of users (currently, only user:admin). Secondly, there is a hkey user:admin with just a password. See the screen below.
With the following code, when I submit my form, it doesn't get in the callback function of the redis' calls :
var username = req.body.username;
var password = req.body.password;
// Now, check if the user he entered exists
client.sismember(['users', 'user:' + username], function(err, reply) {
// IT NEVER GETS THERE
if (reply) {
// If he does, check if the password matches
client.hget(['user:' + username, 'password'], function(err, reply) {
if (reply === password) {
// If the password matches, add the session and redirects to home
req.session.username = username;
res.redirect('/home');
}
else {
options.error = "Password do not match.";
res.render('guest', options);
}
});
}
else {
options.error = "Username does not exist.";
res.render('guest', options);
}
});
I've used console.log to check some stuff, and username and password are well filled in.
There is no error concerning the redis server connection (which I have if I turn the server off), so the problem is not there.
I've tried using client.send_command() instead, but no change.
Any help would be greatly appreciated !
Ok, the answer is pretty stupid. I mean, I am stupid for not seeing this.
The asynchronous nature of this makes it pretty hard to get fully !
The problem was that later, in the code, at the end, I closed redis connection with client.end().
But this function was called before the callback could be fired, even though it was well after in the code.

Resources