Creating a user session - NODE js - javascript

I am new to node js & javascript in general. I have the below piece of code that will handle a login. I have a MYSQL database with a customer table. When the customer enters their username and password, it checks does it exist in the database. This part is working.
I now want to enhance this feature so that it will take the username and create some sort of a session variable, which can be used across the application. I am new to JS so I am not yet sure which inbuilt facilities already exist, or best practice around sessions.
I want to be able to use this session variable across the application, and for subsequent logout facility.
Can someone advise me on this, or point me in the right direction? Thanks.
case "/login":
var body = '';
console.log("user Login ");
request.on('data', function (data) {
body += data;
});
request.on('end', function () {
var obj = JSON.parse(body);
console.log(JSON.stringify(obj, null, 2));
var query = "SELECT * FROM Customer where name='"+obj.name+"'";
response.writeHead(200, {
'Access-Control-Allow-Origin': '*'
});
db.query(
query,
[],
function(err, rows) {
if (err) {
response.end('{"error": "1"}');
throw err;
}
if (rows!=null && rows.length>0) {
console.log(" user in database" );
theuserid = rows[0].customerID;
var obj = {
id: theuserid
}
response.end(JSON.stringify(obj));
}
else{
response.end('{"error": "1"}');
console.log(" user not in database");
}
}
);
});
}

There can be multiple ways of implementing a user session.
One, you could use a browser cookie, it comes with many pros and cons and you should read about it a bit to see how its managed. This would also depend on the server you are using (express, hapi, etc).
Two, you can set a JWT token on the backend, and include it in the header of the response, then you can either use your application state or the local storage of the browser to save that token on the UI. Any such follow up requests requiring authentication should contain this auth token as a header for verification.
For more clarity, you can look into related libraries (such as passport), which make this task a lot easier.
PS: If you choose cookies, please make sure the business is going to allow it or not as the end-users do not like being tracked always. :)

Related

Is this a secure enough method to recover data?

I'd love to know if this method I'm using is secure enough to use on a public project, since I can't really find any other way to retrieve my id from my currently logged in user, but it's a fairly straightforward method , I find. If this method is not secure would it be possible to have a way to proceed? Thanks in advance.
I have a button for example when I use the send of the html that there is inside my div userid on the server to then use this information to make SQL queries from my app.js server.
I use socket.io hbs express node js jwt mysql
From my pages.js file generated with the express library where the main roads of my website are located, I send my user ID.
router.get('/accueil', authController.isLoggedIn, (req, res) => {
if(req.user) {
res.render('./accueil', {
data: req.user.id
});
} else {
res.redirect('/');
}
});
With Handlebars I display this data in my index.hbs (display: none;).
<div id="iduser">{{data}}</div>
Then I get my iduser div on my client.js
let userid = document.getElementById('iduser').innerHTML;
// (My method to display this div)
socket.on('uid', (data) => {
pargent.innerHTML = JSON.stringify(data.data[0].argent);
})
//
So I want to use this userid variable to make SQL queries from my app.js.
(let userid = document.getElementById('iduser').innerHTML;)
I am using socket.io for communication between client and server to send my userid data
Example :
db.query('UPDATE users SET money = money + ? WHERE id = ?', [100, theUserId]);
No
Never trust user supplied data.
References:
https://www.oreilly.com/library/view/http-developers-handbook/0672324547/0672324547_ch22lev1sec1.html
https://flylib.com/books/en/1.290.1.90/1/
https://www.garybell.co.uk/never-trust-user-input/
https://medium.com/#berniedurfee/never-trust-a-client-not-even-your-own-2de342723674
https://www.invicti.com/blog/web-security/input-validation-errors-root-of-all-evil/
https://laravel-news.com/never-trust-your-users
https://www.wearenova.co.uk/nova-blog/when-it-comes-to-online-security-why-you-should-never-trust-a-client
It depends on your authController.isLoggedIn logic,
But I would like to suggest an alternative solution simple as that;
iron-session
Read their docs, it's matches your use case and easy to use; here is equivalent of the snippet you provided with iron session:
//initiate session middleware yourself
router.use(session)
// later here
router.get('/accueil', (req, res) => {
if(req.session.user) {
res.render('./accueil', {
data: req.user.id
});
} else {
res.redirect('/');
}
});

Payment GateWay integration in nodejs and mongodb

Hi I am Integration Payment GateWay to my app but i am stuck. for cod(Cash On Delivery) mode of payment it is working fine.but while in integration online payment gateway it is giving bit pain like i am creating payment link using instamojo when link is created successful; i return that payment link to client and redirect user to that link
1 if user fills card details successfully and instamojo hits my provided webhook(post url) with payment details
2 what if user cancels tab or doesn't pays
question here is where shall in create order in database. if it is to be created on placeorder url of my app then i need to set order status incomplete and run a cron job for second condition (because order is already created and webhook is not hit by intamojo). is it right way to do or there is other better ways to handle all this
Promise.all([getUpdatedCart(userId), findUser(userId), getDiscount(userId,couponCode)])
.then(function(resultArray) {
var cart = resultArray[0];
var user = resultArray[1];
var discountAmount = resultArray[2];
var offerId=null;
if (!cart)
return sendResponse(response,400,"error","Cart Not Found");
if (discountAmount>0)
var offerId=getOfferId(couponCode);
var order = {
user: user._id,
cart: cart._id,
shippingAddress:shippingAddressId,
billingAddress:billingAddressId,
paymenMethod: paymentMethod,
offer:offerId,
deliveryNote:deliveryNote,
amount:cart.amount
};
var newOrder = Order(order);
if (paymentMethod==='cod')
newOrder.save(function(error,order){
if (!error)
if (order){
Cart.expireCart(cart._id);
return sendResponse(response,201,"success",order);
}
});
else if(paymentMethod==='intamojo'){
var purpose='Order Number-'+ newOrder.id;
Instamojo.setHeaders(InstaConfig.test.API_KEY, InstaConfig.test.API_AUTH_TOKEN);
var amountPayable = cart.amount - discountAmount;
var data = generatePayload(user, purpose, amountPayable);
Instamojo.createPaymentLink(data, function(error, resultResponse, body) {
if (resultResponse && body && resultResponse.statusCode===201)
return sendResponse(response,200,"success",body.longUrl+"?embed=form");
});
}
else if(paymentMethod==='payumoney'){
}
else
return sendResponse(response,400,"error","Invalid Mode of Payment");
})
.catch(function(error) {
return sendResponse(response,400,"error",error);
});
Can anyone Please help if i need to write cron job kindly suggest library for that
You need not create a cron job.
You can create Order in your database first, and then create a request passing the orderID in purpose parameter to uniquely Identify the Payment Request.
Provide redirect_url and webhook at the time of create a request.
After any Payment payment_request_id and payment_id is send to the redirect_url provided.
Use payment_request_id and payment_id to get the status of the payment, the response will have payment: { ... ,status, ... } use this to update the status in your database.
You can use webhook as a fallback if the user accidentally closes the browser window/tab before it reaches the redirect_url.
For more details, read the documentation

How to logout from another browser after reset the password

I want to logout from another browser after reset the password.
I use passport.js for user authentication.
So i need a such kind of functionality that if i change my password from one browser then it will automatically logout that user from another browser(When switch to another browser).
Any idea?
function validateToken(token) {
return require("mongoclient").then(function (DB) {
return DB.query({$collection: "pl.connections", $filter: {token: token}});
}).then(function (data) {
if (data && data.result && data.result.length > 0) {
return true;
} else {
return false;
}
})
}
not a complete implementation but a sample code to validate the token in node with mongo
Add A bit of functionality in your app. maintain a table of token in your db corresponding to users so after a change to password just expire the tokens that are in table for a specific user. Its not just a idea its a working strategy that is adopted by many apps.
You can easily archive this using session Id which is generated each time a user is authenticated and is unique to a user. But you have to keep track of the Id
In this solution am using express-session
After a successful authentication req.session.id is assigned to the user, it is an alpha-numeric Id(6QP2t2_ffzkLNPHWNIEuRSXEvNm4lzLb). You can save this user session Id on account login, Then you can retrieve the user's session from the memory store at any time and destroy it:
let session = require('express-session');
const id = req.session.id
sessionStore = express.session.MemoryStore();
sessionStore.get(id, function(err, sess) {
sess.destroy (function (err) {
console.log(err, 'if any')
});
});
For example you can add expireAfter flag to your users table. And when you need to logout somebody just change their expireAfter to current time.
If current timestamp is greater than expireAfter then you just clear cookies in browser when request comes.
And when login just set expireAfter to 1st January of 2030
// something like that
var app = express();
app.use(function(req, res, next) {
var user = { ... } // load user from db
if (user.expireAfter >= new Date().getTime()) {
res.clearCookie('user_id') // or whatever you have
var err = new Error('not authorized, please re-login');
err.status = 403;
return next(err);
}
next();
});
... code code code ...
You can create timer at your client side.
use setInterval function.
Send function that will go to server and check if you need logout.
(This Logic is used to check expire sessions, at some systems)
UPDATE:
following to the comment, I notice that I forgot wrotten critical detail:
Of course, server itself need prevent any action when your password is changed. I meant to client side - that you want to logout it.

Parse.com security: can I save an object and claim it's another user's?

I'm looking at this example of modeling a blog system using javascript, code snippet copied as below:
var user = Parse.User.current();
// Make a new post
var Post = Parse.Object.extend("Post");
var post = new Post();
post.set("title", "My New Post");
post.set("body", "This is some great content.");
post.set("user", user);
post.save(null, {
success: function(post) {
// Find all posts by the current user
var query = new Parse.Query(Post);
query.equalTo("user", user);
query.find({
success: function(usersPosts) {
// userPosts contains all of the posts by the current user.
}
});
}
});
It basically creates a post object and sets the current user object to its user field. To show all blog posts by the current user, it queries all blog posts with the user field set to the current user.
But since the User table by default is read only to all users, wouldn't this be problematic that a malicious user (X) can create random posts and "claim" that they are create by another user (Y), by setting the user field of those posts to Y as he queries from the User table? So the consequence would be that when the system shows posts for user Y, he would see all his true posts in addition to the post that was "forged" by X.
Is the mitigation that the User table needs to be ACL'd somehow? But if it is the solution, then why is the default behavior that an arbitrary user can see the entire User table?
Cloud Code is your friend here.
In this case you want a beforeSave handler that locks the user field to the currently authenticated user on new objects, and rejects the save if they're updating a post and trying to change the user field (or just using ACLs to prevent everyone except the post owner from modifying Post rows).
Something like this:
Parse.Cloud.beforeSave('Post', function(request, response) {
var post = request.object;
var user = request.user;
if (post.isNew()) {
post.set('user', user);
response.success();
} else {
// any special handling you want for updates, e.g.:
if (post.dirty('user')) {
response.error('Cannot change the owner of a Post!');
} else {
response.success();
}
}
});
My recommended approach to handling updates for something like a "Post" would be to prevent all updates. In the "Set permissions" for the class in the Data Browser I would change the following:
Update : Disabled
Delete : Disabled
To disable something just untick the "Any user can perform this action". Optionally you might want to assign a Role like "Administrator" or "Moderator" to allow those people to directly update/delete items.
These functions would then only be possible from Cloud Code when useMasterKey() is used, e.g.:
Parse.Cloud.define('deletePost', function(request, response) {
var postID = request.params.postID;
var query = new Parse.Query('post');
query.get(postID).then(function (post) {
if (post) {
// post found
var postOwner = post.get('user');
if (postOwner.id == request.user.id) {
// we let the owner delete their own posts
// NOTE: need to use the master key to modify/delete posts
Parse.Cloud.useMasterKey();
post.destroy().then(function () {
// TODO: delete all replies too?
response.success();
}, function (error) {
response.error(error);
});
} else {
response.error('Only the owner of a post can delete it!');
}
} else {
// post not found, might as well respond with success
response.success();
}
}, function (error) {
response.error(error);
}
});
But since the User table by default is read only to all users,
wouldn't this be problematic that a malicious user can create random
posts and "claim" that they are create by another user, by setting the
user field to the other user?
You can play around with curl to explore this.
IMO - you are right about world read on the _User class. So what. That is read.
When it comes to POST action, you are going to need an authenticated session as the user in question. You cant just spuuf things by claiming that u are a user that you read on the table.
try curl posts without an established session as the user. You will get a 403 or some 'illegal access' response.

LDAP - Find user by name only

I am not too familiar with LDAP, however I am working on authentication in a Node.js app, and the user credentials for the web app is going to be gotten from the organization's Windows domain.
I have LDAP lookups working (using the Passport.js Node module), however to make it work, I have to put the user's full-fledged DN into Node. For example, let's say:
My FQDN is mydomain.private.net.
My users are stored in an organizational unit, let's say staff.
Now, if I want to lookup user joe, I have to put this string into Node:
var username = 'CN=joe,OU=staff,DC=mydomain,DC=private,DC=net';
do i really have to keep track of all that?
What if my users are in two different organizational units? The client-side browser doesn't know that! It just knows:
username = 'joe';
password = 'xxxxx';
What if you try to log on as administrator? Administrators are always in a totally different OU by default.
Is there a way to reference an LDAP object by just the name and nothing else?
This is a general LDAP problem. You need to get a unique identifier from the user, and then look for it.
Typically this is what the uid attribute is used for. Active Directory may or may not have that populated, and generally relies on sAMAccountName which must be unique within the domain.
So you need a two step process.
1) Query for uid=joe or samAccountName=joe
2) Use the results to test a bind or password compare.
You would then use the DC=mydomain,DC=private,DC=net value as the root to search from.
(answer to my own question)
geoffc's answer was correct, and this is the working solution adapted to my Node.js app using the activedirectory npm module:
// First search for the user itself in the domain.
// If successfully found, the findUser function
// will return the full DN string, which is
// subsequently used to properly query and authenticate
// the user.
var AD = self.ADs[domain];
AD.findUser(username, function(err, user) {
if (err) {
cb(false, 'AD error on findUser', err);
return;
}
if (!user) {
cb(false, 'User does not exist', void 0);
} else {
username = user.dn;
AD.authenticate(username, password, function(err, authenticated) {
if (authenticated == false) {
cb(false, err, void 0);
return;
} else {
cb(true, 'Authenticated', void 0);
}
});
}
});

Categories