How to load a specific session using express-session in node.js? - javascript

I need to create a websocket where I can connect to it from a different domain (websocket runs on 10.0.4.18:8020 and the client will establish connection from 10.0.4.160:443.)
Each user must have a unique session to be able to reuse his/her user data after authentication takes place.
Since the client "aka user's browser" is on a different host, I am having hard time keeping the session tied with with the client that creates it on page reloaded event!
I thought of this workaround to solve this problem
Create session using XMLHttpRequest() function from the client, then return a sessionID to the client
Save the sessionId in the user's browser using localStorage
Pass the sessionId to socket.io every time a user connects to the websocket.
Websocket then takes the sessionId and reloads it to make it available all over again.
To eliminate session fixation attack, I am going to add few more validation step to make sure the sessionId is not hijacked by using the client's IP and agent data.
Additionally, I need to fire a setInterval() method which will make external API call every second and updates the session variable.
Question
How can I properly reload a session data where I can auto save the variables without having to directly use store.get() to load the session data and save them?
Here is what I have done
I created the session using a file system. On every request I have to load the session store using store.get() method, update the session data, and then save it. But the problem that I have is every time I want to update the session as you can see my below code.
Here is what I have done!
var app = require('express')(),
https = require('https'),
fs = require('fs'),
session = require('express-session'),
fileStore = require('session-file-store')(session),
base64url = require('base64url'),
bodyParser = require("body-parser");
cookieParser = require("cookie-parser"),
env = require('./modules/config');
var server = https.createServer(
{
key: fs.readFileSync('certs/key.pem'),
cert: fs.readFileSync('certs/cert.pem')
}, app).listen(env.socket.port, env.socket.host, function () {
console.log('\033[2J');
console.log('Websocket is running at https://%s:%s', server.address().address, server.address().port);
});
var io = require('socket.io')(server);
var icwsReq = require('./modules/icws/request.js'),
icwsConn = require('./modules/icws/connection.js'),
icwsInter = require('./modules/icws/interactions.js'),
sessionValidator = require('./modules/validator.js');
var icwsRequest = new icwsReq();
var sessionChecker = new sessionValidator();
var sessionStoreFile = new fileStore({path: './tmp/sessions'});
var sessionOptions = {
store: sessionStoreFile,
secret: env.session.secret,
saveUninitialized: true,
resave: false,
cookie: {
path: '/',
httpOnly: true,
maxAge: 60 * 60 * 1000,
secure: true
}
};
app.use(session(sessionOptions)); // session support for the app
app.use(bodyParser.urlencoded({ extended: false })); //allows to pupulate req.body in the REST/PUT post requests!
// Set access control headers on every express route.
app.use(function (req, res, next){
res.setHeader('x-powered-by', 'Express');
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST');
next();
});
//Middleware for authorizing a user before establishing a connection
io.use(function(req, next) {
var sessionID = req.handshake.query.token || '';
var token = req.handshake.query.auth || '';
var origin = req.handshake.headers.origin;
var ip = req.request.socket.remoteAddress;
var userAgent = req.handshake.headers['user-agent'];
if(!sessionID || !token){
console.log('No Session found with this token! ' + sessionID);
return next(new Error('No Session found with this token!'));
}
sessionStoreFile.get(sessionID, function(err, session){
// session updated
if(err){
console.log(err);
return next(new Error(err));
}
if(!session){
console.log('Session Could not be loaded');
return next(new Error('Session Could not be loaded'));
}
if( session.token != token
|| session.ip != ip
|| session.agent != userAgent
|| session.origin != origin
){
session.token = null;
session.ip = null;
session.agent = null;
session.origin = null;
sessionStoreFile.set(sessionID, session);
console.log('This session is invalid! Please sign in');
return next(new Error('This session is invalid! Please sign in'));
}
next();
});
});
io.on('connection', function (socket) {
var sessionID = socket.handshake.query.token;
//load the session with the ID sessionID
sessionStoreFile.get(sessionID, function(err, session){
//add the socket.id to the queue
session.clients.push(socket.id);
//Save the session data after adding the connection to the queue
sessionStoreFile.set(sessionID, session, function(){
//Get the current session data "including current socket.id"
sessionStoreFile.get(sessionID, function(err, session){
//get an instance of icws connector
icwsRequest.setConnection(session.icwsHost, session.icwsPort);
var interactions = new icwsInter(icwsRequest);
//Call the API everysecond, update the session then save the session
setInterval(function(){
sessionStoreFile.get(sessionID, function(err, session){
//call the API and return the new data
session.queue = interactions.updateQueue();
//save the new data every second
sessionStoreFile.set(sessionID, session);
}
}, 1000);
//handle ICWS interactions
socket.on('interaction', function(data){
var task = data.task || '',
phone = data.phone || '',
interactionId = data.interactionId || '',
queueName = data.queueName || '';
//Place a phone call
if(task == 'call'){
interactions.call(phone);
}
//External transfer
if(task == 'eBlindTransfer'){
interactions.blindTransferCallExternal(interactionId, phone);
}
//Internal Transfer
if(task == 'iBlindTransfer'){
interactions.blindTransferCallInternal(interactionId, queueName);
}
});
//send a chat message to all browser's tabs associated with the currect session
socket.on('chat', function(msg){
var clients = session.clients;
console.log(clients);
for (var i in clients) {
var socketId = clients[i];
console.log('Client Said: ' + msg + ' socket Id: ' + socketId);
io.to(socketId).emit('chat', {message: 'Server Said: ' + msg});
}
});
//handle disconnect
socket.on('disconnect', function(msg){
var index = session.clients.indexOf(socket.id);
if(index > -1){
session.clients.splice(index, 1);
//save session after removing a client
sessionStoreFile.set(sessionID, session, function(error){
if(!error){
console.log('Closing tabs: ' + socket.id);
console.log(session);
}
});
}
});
//handle errors
socket.on('error', function(msg){
console.log('Error Message: ' + msg);
});
});
});
});
});
app.get('/', function (req, res) {
res.send('welcome: ' + req.sessionID);
});
app.get('/handshake/:token', function (req, res) {
var origin = req.headers.origin;
var ip = req.connection.remoteAddress;
var userAgent = req.headers['user-agent'];
if(!req.params || !req.params.token || !ip || !origin || !userAgent){
console.log('Missing Request!');
return false;
}
if(!originIsAllowed(origin)){
console.log('This is a cross-domain attack!');
return false;
}
req.session.token = req.params.token;
req.session.ip = ip;
req.session.origin = origin;
req.session.agent = userAgent;
req.session.clients = [];
req.session.save(function(err){
if (err) {
connectionError(res, session);
} else {
res.json({
token: req.sessionID
});
}
});
});
function originIsAllowed(origin) {
// put logic here to detect whether the specified origin is allowed.
var allowed = env.session.allowedOrigins || []
if(allowed.indexOf(origin) >= 0){
return true;
}
return false;
};

Related

Trying to make a get request using NodeJS

I am trying to make a get request to my NodeJS server side but it keeps saying CERT_UNTRUSTED.
The code that I am using on the client side is:
function validateUser(){
var userEmail = $("#userEmail").val();
var userPassword = $("#userPassword").val();
$.ajax({
url: "https://changelog.twvending.net/ValidateUserByName?userName="+userEmail+"&userPassword="+userPassword,
success: function(user){
if (user === "bad user"){
alert("Your credentials are incorrect, please try again");
} else {
if (user.User.PermissionLevel === 3){
localStorage.setItem("permission", "hello");
$("#newEntry").show();
window.location.href = "https://changelog.twvending.net";
}
else {
alert("You do not have permission to make new entries");
window.location.href = "https://changelog.twvending.net";
}
}
},
error: function(xhr,status,error){
}
});
}
and on the server side
app.get('/ValidateUserByName', function (req, res) {
res.setHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));
var userEmail = req.query.userName;
var userPassword = req.query.userPassword;
processInput(userEmail +" logged in");
var request = require('request');
request.get('https://32market.com/32marketpcitest/threesquaremarketrest.svc/ValidateUserByEmailULR?email='+userEmail+'&password='+userPassword,
function (err, resp, body) {
if (err){
processInput ( err )
console.log('Error: ' + err);
return;
}
try {
var user = JSON.parse(body);
res.send(user);
}
catch(err) {
processInput('error logging in: invalid user name or password');
res.send("bad user");
}
});
});
My question is what am i missing that the client or sever is not liking. I should also note that this is my first time doing a project like this.
My guess is you don't have the required Or expired ssl certificates to do your request. Probably to 32market.com does it use an https connection? Is it your own site?
You can try adding
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
Before your request
But that isn't exactly secure.

Have set up mongodb, mongoose etc but when I try and add something to the database it doesn't actually add it

I'm using localhost and have all the modules set up correctly and I've checked that the database exists. When I type in localhost:3000/pods/add?firstName='John' it's supposed to add it to the database, but for some reason it isn't working.
var express = require('express');
var _ = require('underscore');
var mongoose = require('mongoose');
var podStore = require('./lib/pod-handler.js');
var podsLibrary = require('./lib/pods-library.js');
var podList = [];
var mongoPort = 27017;
var app = express();
var port = 3000;
var router = express.Router();
var pods = podsLibrary.list();
mongoose.connect('mongodb://localhost:'+mongoPort+'/pods');
router.route('/').get(function(request, response) {
//console.log('You hit an empty URL .. :(');
response.status(503).send("Service Unavailable");
});
router.route('/lib').get(function(request, response) {
//console.log('You hit an empty URL .. :(');
response.status(200).send("Cool beans!");
});
router.route('/pods/list').get(function(request, response){
if(!pods){
return response.status(503).send("Service Unavailable");
}
return response.status(200).send(makeReadableList(pods));
function makeReadableList(pods){
var podsHtml = " ";
_.each(pods, function(value, key){podsHtml = podsHtml + key});
return podsHtml;
}
});
router.route('/pods/add').post(function(request, response){
if (!request.query){
return response.status(400).send("Please give first name");
}
var payload = request.query;
if (!payload.firstName){
return response.status(400).send("give name");
}
podStore.save({
firstName: payload.firstName,
lastName: payload.lastName
}, function(){
return response.status(200).send(payload.firstName + " has been added!");
var space = " ";
_.each(pods, function(value, key) {
key + space;
return space + payload.firstName + payload.secondName;
});
});
});
router.route('/pods').get(function(request, response) {
//console.log("We reached the POD page -- Yay! :D");
response.status(200).send("Server unavailable");
});
app.use('/', router);
app.listen(port, function () {
console.log('App listening on port %s', port);
});
I've checked over my code countless times and I can't seem to find the problem.
Here's the pod-handler file.
var PodDoc = require('../models/pods.js');
module.exports = {
save: save
}
function save(pod, callback){
var podToSave = new PodDoc();
podToSave.firstName = pod.firstName;
podToSave.lastName = pod.lastName;
/*podToSave.skills = pod.skills;
podToSave.avatarUrl = pod.avatarUrl;
podToSave.address = {
number: pod.address.number,
lineOne: pod.address.lineOne,
lineTwo: pod.address.lineTwo,
postcode: pod.address.postcode
}
podToSave.phoneNumbers = {
mobile: pod.phoneNumbers.mobile,
landline: pod.phoneNumbers.landline
}*/
podToSave.save(function(err){
if(err){
console.log(err);
} else {
console.log("Working");
callback();
}
})
}
When I type in localhost:3000/pods/add?firstName='John' it's supposed to add it to the database
If i understand correctly, you want to open this url in browser, and expect to have a record John in database.
Change router request type to GET, this
router.route('/pods/add').post(/*omitted*/);
to this
router.route('/pods/add').get(/*omitted*/);
Server is expecting POST request, but browser cannot handle it without FORM element or ajax request, browsers usually uses GET request, i mean when you open your url, it send GET request to server
There may be a typo error as in the url you are using port 300 where as the port configured for localhost is 3000.
When I type in localhost:300/pods/add?firstName='John'

How to get response from other user after joining room using socket.io

i have one doubt regarding socket.io.I have two type of user i.e-admin,client .First admin will create userid and join to the room.I need when user will join room the admin should get response and need help regarding this.
My working codes are given below.
server.js:
var port=8888;
var express=require('express');
var morgan = require('morgan');
var http=require('http');
var bodyParser= require('body-parser');
var methodOverride = require('method-override');
var mongo = require('mongojs');
var database='Oditek';
var collections=['video'];
var app= express();
var server=http.Server(app);
var io=require('socket.io')(server);
var db = mongo.connect("127.0.0.1:27017/"+database, collections);
app.use(express.static(__dirname + '/public')); // set the static files location /public/img will be /img for users
app.use(morgan('dev')); // log every request to the console
app.use(bodyParser.urlencoded({ extended: false })) // parse application/x-www-form-urlencoded
app.use(bodyParser.json()) // parse application/json
app.use(methodOverride()); // simulate DELETE and PUT
db.on('ready', function () {
console.log('database connected')
});
app.get('/',function(req,res){
res.sendfile('view/login.html');
});
app.post('/login',function(req,res){
var username=req.body.username;
var password=req.body.userpassword;
if(username && password){
db.video.findOne({
username:username,
password:password
},function(err,doc){
if(doc){
console.log('login',doc);
res.send(doc);
}
if(err){
console.log('login12',err);
res.send("could not login");
}
});
}
});
app.get('/video',function(req,res){
res.sendfile('view/video.html');
});
//socket----programming//
var roomid;
io.on('connection',function(socket){
//console.log(socket);
roomid=socket.handshake.query.roomid;
var usertype=socket.handshake.query.usertype;
socket.join(roomid);
});
server.listen(port);
console.log('server is listening on the port'+port);
My client side code is given below.
function videoBroadCasting(uType){
var messageGateWay;
if(uType=='admin'){
var userid = getRandomString();
$('#styled').val('http://localhost:8888/video?usertype=client & id='+userid);
messageGateWay=io('http://localhost:8888/?roomid='+userid+'usertype='+uType);
}
if(uType=='user'){
messageGateWay=io('http://localhost:8888/?usertype='+uType);
}
messageGateWay.on('connect',function(){
console.log('socket get connected');
});
}
function getRandomString() {
return (Math.random() * new Date().getTime()).toString(36).replace(/\./g, '');
}
function getQuery(key){
var temp = location.search.match(new RegExp(key + "=(.*?)($|\&)", "i"));
if(!temp) return;
return temp[1];
}
After client is joining the room the admin should get one notification.Please help me to do this.
One simple solution is to save the socket object from the admin in the server when the admin joins the room. Then, when some other user join the room, simply emit a message to that socket from the admin/admins. Just keep an array update with the admins actually logged in the room.
Something like:
var socketAdmin = {};
io.on('adminJoins',function(socket){
socketAdmin = socket;
roomid=socket.handshake.query.roomid;
var usertype=socket.handshake.query.usertype;
socket.join(roomid);
});
io.on('clientJoins',function(socket){
roomid=socket.handshake.query.roomid;
socketAdmin.emit('newClient', {socketClient: socket, roomId: roomid};
var usertype=socket.handshake.query.usertype;
socket.join(roomid);
});
In this example, the client sends a message 'adminJoins' if you are an admin, or 'clientJoins' ir you are a client, you can send that checking the uType var you have. In case a new client joins the room, the admin recieve a 'newClient' message with the socket of the client and the roomId (just an example).

How do I close a sockjs connection on the server side?

So, every time I refresh the page, it seems like sockjs is creating a new connection.
I am saving every message to my mongodb on every channel.onmessage, so if I refresh my page 7 times and send a message, I would save 7 messages of the same content into my mongodb.
This is very problematic because when I retrieve those messages when I go into the chat room, to see the log, I would see bunch of duplicate messages.
I want to keep track of all connections that are 'active', and if a user tries to make another connections, I want to be able to force close on the old one from the server side, so there is only 1 connection listening to each message at a time
How do I do this ?
var connections = {};
//creating the sockjs server
var chat = sockjs.createServer();
//installing handlers for sockjs server instance, with the same url as client
chat.installHandlers(server, {prefix:'/chat/private'});
var multiplexer = new multiplexServer.MultiplexServer(chat);
var configChannel = function (channelId, userId, userName){
var channel = multiplexer.registerChannel(channelId);
channel.on('connection', function (conn) {
// console.log('connection');
console.log(connections);
connections[channelId] = connections[channelId] || {};
if (connections[channelId][userId]) {
//want to close the extra connection
} else {
connections[channelId][userId] = conn;
}
// }
// if (channels[channelId][userId]) {
// conn = channels[channelId][userId];
// } else {
// channels[channelId][userId] = conn;
// }
// console.log('accessing channel! ', channels[channelId]);
conn.on('new user', function (data, message) {
console.log('new user! ', data, message);
});
// var number = connections.length;
conn.on('data', function(message) {
var messageObj = JSON.parse(message);
handler.saveMessage(messageObj.channelId, messageObj.user, messageObj.message);
console.log('received the message, ', messageObj.message);
conn.write(JSON.stringify({channelId: messageObj.channelId, user: messageObj.user, message: messageObj.message }));
});
conn.on('close', function() {
conn.write(userName + ' has disconnected');
});
});
return channel;
};
Simply use .close:
if (connections[channelId][userId]) {
// want to close the extra connection
connections[channelId][userId].close();
} else {
connections[channelId][userId] = conn;
}

Sessions and socket.io (node.js, express.js)

How to get user session with socket.io?
io.sockets.on('connection', function(socket) {
// Need to get user session
});
You can attach session with socket and get in connection event. Get the user session in authorization, if you're using express then do this:
var sessionStore = new express.session.MemoryStore();
io.set('authorization', function (handshake, accept){
var cookies = require('express/node_modules/cookie').parse(handshake.headers.cookie);
var parsed = require('express/node_modules/connect/lib/utils').parseSignedCookies(cookies, 'SESSION_SECRET');
sessionStore.get(parsed.sid, function (error, session){
if (session != null && session.user != null){
accept(null, true);
handshake.session = session;
}
});
});
And in your connection event you can get it like:
socket.handshake.session

Categories

Resources