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

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.

Related

What request status should I apply on wrong client applies?

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.

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,
});
}

how can I do, if user logined, he can change only his profile nodejs/mongodb/mongoose/pug

So basically I have a dynamic route that routes to every user username in DB
router.get('/:username', function (req, res) {
User.findOne({username:decodeURI(req.params.username)}, function (err, user) {
if (err) throw err;
if (user == null) {
}else if(user !== null){
res.render('user-profile', {
user:user
});
}
});
});
And I want to check for example: if the user that logged in is "alpha", and he seeing his profile on this URL: http://localhost:8080/users/alpha, then display him private information so only he can see it.
And if "beta" wanna see "alpha" profile, he doesn't see any private information of alpha
I'm working with passport, passport-local and express session
It is not as Complicated as you think . So, Lets discuss the scenario There are two users A and B . What we want to achieve here is that the url /users/:username only displays the public information of the user and if username is same as that of the logged-in user in that case it would also display the private information of the logged in User
A very simple approach would be to list all the information (public and private) but only display the private information on the profile page if the id or username for /users/:username is same as the logged in user.(can easily be acheived through any template engine)
if you are using passport then the logged in users info gets attached to the req object that you could use to simply check whether you need to display the information or not.

Facebook API Nodejs

I'm trying post a message as admin of a facebook page, but my code keeps posting as my personal account to the "wall" of the page, not as the page itself.
When authorizing my application I ask for the right permissionscopes, and accept them. Although, when I check my permissions with /{USER-ID}/permissions, it says that I've denied the application to manage my pages. Any ideas why?
Here's my code for posting:
var parameters = {};
parameters.message = "Hello world, this is dog.";
parameters.access_token = req.session.access_token;
FB.api('{PAGE-ID}/feed', 'post', parameters, function (result) {
if (!result) {
return res.send(500, 'error');
} else if (result.error) {
if (result.error.type == 'OAuthException') {
result.redirectUri = FB.getLoginUrl({ scope: 'publish_actions,manage_pages,publish_pages', state: encodeURIComponent(JSON.stringify(parameters)) });
}
console.log(result);
return res.send(500, result);
}
res.send(result);
});
And yes, of course I use my page id instead of the placeholder in my code above.
*Update: It seems like the permissions aren't even asked for when authorizing the application. I added the email scope to the list and it appears when I re-authorize the application.
Could this have anything to do with my application not beeing approved?
"Submit for Login Review
Some of the permissions below have not been approved for use by Facebook.
Submit for review now or read more."

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