Redis and NodeJs - Can't auth a user - node.js

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.

Related

Just dont understand the use of .isModified function in node (why do we hash password in pre hooks?)

I'm sorry, I know this is pretty basic but I just don't understand this! I've just gotten done doing JS for two years and now I wanna learn node, so far nothing has troubled me but this code:
userSchema.pre("save", async (next) => {
let user = this;
if (user.isModified("password")) {
user.password = await bcrypt.hash(user.password, 9);
}
next();
});
My first question is what exactly does that isModified function do? Intuitively it makes most sense for "user.isModified("password")" to return true if in the middleware chain, from the first time we got the request object, the property 'password' was modified.
Is that right? And even if it is, I dont understand how will that property change, the only way user's password property is changing is if we do it explicitly and in our case the only time we'll do that is if we want to hash the password.
My second question is, why do we have to hash password in the hooks, pre in this case? And with the help of .isModified method? I'm following three instructors and all of them did it this way but no one really explained the use of it behind the scene.
FindByIdAndReplace, findByIdAndUpdate etc also experience the 'save' event but we dont want any hashing there so why we taking the risk of putting our hashing code in pre save hook? I'm doing it this way and it seems to be working fine:
app.post("/signup", async function (req, res) {
let { email, password } = req.body;
let user = await Bank.create({ email, password });
user.password = await bcrypt.hash(password, 11);
await user.save();
});
What's wrong with the code above?
Sorry if this is long but I really had to ask this, I've already spent weeks on this but I just dont get it!

How to add current logged in status to Users Schema in MongoDB using Passport and node.js

I’m quite new to backend development…
With using my API I would like to be able to display a list of users and also indicate if they are currently logged in. I got the basic authentification working using passport and json web token
I’m not looking to get the current logged in user.
I want to be able to retrieve a list of users and see if they are logged in or not.
Like this:
var users = Users.find({});
// console.log(users) output:
{
name: 'foo'
password: ...
isLoggedIn: false
},
{
name: 'bar'
password: ...
isLoggedIn: true
},
{
name: 'baz'
password: ...
isLoggedIn: false
}
isLoggedIn would be set to true if the user is currently logged in and to falseif not.
How can I do that? Thank you!
It sounds like what you would like to do is update your MongoDB database based on login/logout events. To do this you could use something like mongoose to work with your Node backend to easily access your database in MongoDB.
You can include mongoose after installing with npm install mongoose like so:
var mongoose = require('mongoose');
var User = mongoose.model('User');
Note that User corresponds to whatever schema you create for storing user information.
Assuming you have some sort of router object for handling requests, you could construct route handlers for /logout and /login and use your imported mongoose User model to retrieve and then modify a specific User object as such:
// whenever user goes to '/login' (you can have, say, your 'login' button make a request to this URL
router.get('/login', function(req,res) {
// your authentication here; passport stores the currently authenticated user in req.user
var username = req.user.name; // here we assume the username is stored as 'name' as you have in your code but change this based on your schema
User.findOne({name: username}, function(err, user, data) {
if(err) res.send(err);
user.isLoggedIn = true;
user.save(function (err) {
if (err) {
console.log(err);
} else {
// redirect to some page here maybe
}
});
});
});
// whenever user goes to '/logout' (you can have a logout button make a request to this URL
router.get('/logout', function(req,res) {
// currently authenticated user is still in req.user
var username = req.user.name;
User.findOne({name: username}, function(err, user, data) {
if(err) res.send(err);
user.isLoggedIn = false;
user.save(function (err) {
if (err) {
console.log(err);
} else {
// redirect to login/register page maybe
}
});
});
});
So to summarize what this code would do:
based on the url a user would go to, our route handler would fetch one correct, unique User object from our database based on the name (username)
it would do so by accessing the username property of req.user which corresponds to the currently authenticated user with Passport, which, again will be different for all users
update the field that we use to keep track of login status (isLoggedIn)
and then save the changes, after which we are done updating the state to reflect whether the user is logged in or not, so we can now redirect to some other page or display other content
Finally then, you could retrieve a list of all users similarly to your code like so:
User.find({}, function(err, users, data) {
// all users from your database are in `users`
console.log(users);
});
Edit for expired sessions:
So, to track expired sessions, since you're using Passport, would in theory require functionality to signal with some sort of event / callback / message, etc. the moment the session is deemed invalid. Now that is tough to monitor and from my experience with Passport, stuff like that isn't implemented in all authentication strategies and might vary based on the strategy to be used by developers (think for instance if a browser window is closed, based on Passports authentication strategy, or just browser, it might destroy the cookie for the session right away and our server has no way of knowing about it). I do recommend checking out all the authentication strategies Passport offers in case there are some better ones here.
Now, if you would like to add functionality to track the users passive login/logout status with sessions yourself, you could use something related to cookies. Again, not necessarily one to use, but here's a couple handy Express modules: cookie-parser and cookie-session.
Then, you could set and read cookies like this, using cookie-parser:
var express = require('express');
var cookieParser = require('cookie-parser');
var app = express();
app.use(cookieParser());
You would put this code somewhere right after the user is authenticated:
// cookies are stored here
console.log(req.cookies);
// configure your cookie
var options = {
expires: 1000 * 60 * 60, // expires after one hour
httpOnly: true
}
// Set cookie
res.cookie('session', ('user-' + req.user.name), options);
And then, on the client side check if that cookie is valid continuously on some time interval, and if it expired Date.now() > cookie.expires then make a GET request to /logout, and there log out the user (currently still authenticated) by updating MongoDB and all.
However, since this would require making a mechanism to basically simulate an expired session, I would recommend using something analogous to a timeout, which would be much easier to implement. Just a note, this is sort of analogous to mechanisms on some pages you might have encountered where you get a pop-up saying 'You will be logged out due to inactivity'. In your main.js or whatever client-side script define a function to keep going on a time-out, unless the user does some action.
var inactivity = function () {
var t;
// user doing something on your page, so keep resetting time counter when events happen
document.onmousemove = resetTimer;
document.onkeypress = resetTimer;
// this is a callback function that will get called once a time-out countdown is done
function timeOut() {
// make a request to '/logout' here and logout the current user (you still will have access to req.user from Passport)
// also can redirect from back-end route handler to the login page for instance
}
// this gets called whenever an event happens, resetting the counter of sorts
function resetTimer() {
t = 0;
t = setTimeout(timeOut, 1000 * 60 ) // set this to however long you should wait to log out your user time (in milliseconds)
}
};
So basically what this approach would let you do, is automatically invalidate sessions yourself, which means you would have much greater control over updating the state of your database and logging users out.
Hope this helps!

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.

Node/Express/Jade passing username back to view

This is my first project with all these technologies, I typically do Angular, but I am working for a charity ( and keen to learn node ). This is day three.
During a login, this is the method called:
schema.statics.authenticateAndLoad = function(req, res, next) {
var userId = req.body.email;
res.locals.userId = userId;
This is supposed to store the value so it doesn't need to be reentered. If login fails, it does this:
return next('Login failed. Please enter your details and try again.');
Then in my Jade template:
if(locals.userId)
p Welcome to #{userId}
else
p Welcome
The actual template has code to try to do what I want:
input(type='text', name='email', id="inputEmail", placeholder="Email", value="#{body.email || ''}")
But this does not work.
So, I THINK this means my setting a value in the result is lost when I call 'next', but, because it's also passing in this error object to show on the screen, I'm not sure how I would go about making sure this error shows AND make the value pass through . Right now, my text just says 'welcome' and never 'welcome to xx', this is test code, I'm just proving the value is not being passed through.
My question is, what's the correct way to pass the value through to my template, and ALSO trigger the error message that is being shown.
The code, when I step in to it, goes deep in to Express and checks for errors there.
Hi it is good to see some developers doing charity work.
Typically what you would use is something like this assuming this is a piece of middleware
schema.statics.authenticateAndLoad = function(req, res, next) {
var userId = req.body.email;
res.locals.userId = userId;
loginFunction(userdetails,function(error,result){
//if there is an error you need to render the page or do a redirect to the
//login page
if(error){
var msg = 'Login failed. Please enter your details and try again.'
return res.render('login',{userId: userId,error: msg})
//this renders the login page and passes req.body.email to the page as userID and the msg as error
}
if(result){
//if this is correct you return next() as you are saying
//you may go through
return next()
}
}
}
then on your jade to display the error you use and userID
p #{userID}
p #{error}
So to answer your question the correct way to send the value to jade you pass it in using this and pass the error in as a variable.
return res.render(template_name,{userId: req.body.email,error: msg})
I hope this helps you out

Tidy callbacks node.js

Trying to think of a logical way of structuring this. For simplicity, I am creating a user registration page utilising Node.js, Redis and Express.js.
User posts details to page.
Username is confirmed to be valid then Redis checks username is unique. If it is, we continue, if it isn't we return an error message and all the previous details.
Password is confirmed to be valid. If it isn't an error is returned and we don't continue.
Email is confirmed to be unique with Redis. If it is we continue, if it isn't we return an error message and stop.
If no errors at this point, the data is inserted into Redis.
This seems very simple, but using callbacks has generated a total mess - particularly when it comings to returning an error.
How can I structure this in a tidy way?
What you've experienced is callback hell. There are a variety of things you could do like name your callback functions instead of inlining them, follow the same pattern etc...
However, I would recommend you have a look at the async module.
In your, very typical, case I would use async.series like this:
var validateUserName = function(username, callback){
if(username!='valid'){
return callback('invalid username');
}
};
var checkRedis = function(username, callback){
// check to redis
};
var checkPassword = function(password, callback){
// if password valid callback();
// else callback('invalid password');
}
etc...
async.series([checkUserName, checkRedis, checkPassword, etc...], next);

Resources