Getting the current user in express.js, while using socket.io? - javascript

I'm using the express framework, and part of my web app uses socket.io to enable real-time chat. I need to get the current user's username, and create a room with him in it. The problem is I can't find a way to get the user info when socket.on('connection') is called. Here's the relevant code I have so far :
var express = require('express');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var mongoose = require('mongoose');
var session = require('express-session');
var http = require('http');
var routes = require('./routes/index');
var app = express();
var server = http.createServer(app);
var io = require('socket.io')(server);
server.listen(4000);
app.use(session({secret : 'anything',
saveUninitialized: true,
resave: true}));
app.use(passport.initialize());
app.use(passport.session());
mongoose.connect('mongodb://localhost/my_db');
var Schema = mongoose.Schema;
var UserDetail = new Schema({
username: String,
password: String
}, {
collection: 'users'
});
var UserDetails = mongoose.model('users', UserDetail);
app.use('/', routes);
app.use('/users', users);
app.post('/login',
passport.authenticate('local', {
successRedirect: '/loginSuccess',
failureRedirect: '/loginFailure',
})
);
io.on('connection', function(socket) {
console.log('socket stuff');
var sessionStore = session;
var sessionId = socket.handshake.sessionId;
sessionStore.get(sessionId, function(err, session) {
if(!err) {
console.log('no error');
if(session.passport.user) {
console.log('This is the users email address %s', session.passport.user);
}
}
});
socket.emit('newMessage', {content : 'Chat message content'});
});
The last function is where I'm having trouble. When a user requests a page, I can just find their username by req.user, but I have no idea how to do it when I don't have req. The code I have for sessions in io.on('connection') does not work at all, and just throws errors, figured I'd keep it in to show what I've tried so far.

This has been asked a few times but the older answers I found do not work anymore. The answer lies in parsing socket.handshake.headers.cookie but this is hacky and will depend on the internals of express-session.
Anyways, this should work for now with Express 4 and socket.io 1.1:
var express = require('express'),
session = require('express-session'),
cookie = require('cookie'),
signature = require('cookie-signature');
var app = express(),
store = new session.MemoryStore(),
secret = 'session-secret-key',
name = 'connect.sid';
app.use(session({
name: name,
secret: secret,
store: store,
resave: true,
saveUninitialized: true
}));
var server = require('http').createServer(app),
io = require('socket.io')(server);
io.on('connection', function(socket) {
if (socket.handshake && socket.handshake.headers && socket.handshake.headers.cookie) {
var raw = cookie.parse(socket.handshake.headers.cookie)[name];
if (raw) {
// The cookie set by express-session begins with s: which indicates it
// is a signed cookie. Remove the two characters before unsigning.
socket.sessionId = signature.unsign(raw.slice(2), secret) || undefined;
}
}
if (socket.sessionId) {
store.get(socket.sessionId, function(err, session) {
console.log(session);
});
}
});

Related

node.js Googe Authentication callback error

I'm trying to set up Googe Authentication to a website running off node.js, passport.js, express & mongodb, largely based off this example. I have managed to get local authentication working but when trying to get Google Authentication working, I'm getting a TypeError: OAuth2Strategy requires a verify callback error when trying to initialise the server.
The authentication strategy for Google is held in /config/passport.js, shown below:
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy();
var User = require('../models/user');
var configAuth = require('./auth');
module.exports = function(passport) {
// serialize the user session
passport.serializeUser(function(user, done) {
done(null, user.id);
});
// deserialize the user session
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
// =================GOOGLE=======================
var strategyOptions = {
clientID : configAuth.googleAuth.clientID,
clientSecret : configAuth.googleAuth.clientSecret,
callbackURL : configAuth.googleAuth.callbackURL,
};
var verifyCallback = function(token, refreshToken, profile, done) {
process.nextTick(function() {
User.findOne({ 'google.id' : profile.id }, function(err, user) {
if (err)
return done(err);
if (user) {
return done(null, user);
} else {
var newUser = new User();
newUser.google.id = profile.id;
newUser.google.token = token;
newUser.google.name = profile.displayName;
newUser.google.email = profile.emails[0].value;
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
};
passport.use(new GoogleStrategy(strategyOptions, verifyCallback));
};
My app.js looks as follows (with the invocation of passport.js bolded):
// set up ================================================================
var express = require('express');
var app = express()
var path = require('path');
var mongoose = require('mongoose');
var passport = require('passport');
var flash = require('connect-flash');
var morgan = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
var configDB = require('./config/database.js');
// config ================================================================
mongoose.connect(configDB.url);
require('./config/passport')(passport);
//set up express application
app.use(morgan('dev'));
app.use(cookieParser());
app.use(bodyParser());
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(session({ secret: 'what a long string' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use(express.static(path.join(__dirname, 'public')));
// routes ================================================================
require('./routes/index.js')(app, passport);
// launch ================================================================
//app.listen(port);
module.exports = app;
I can't tell what is going wrong here, because as far as I can see verifyCallback is being supplied in the passport.use() function. I've spent the last day Googling around and searching through StackOverflow but haven't found a fix that works yet.
Apologies if this is a really obvious error, I'm new to the whole node ecosystem and web design in general. Happy to provide more information if that is helpful.
You have done it well.The issue is with getting google strategy.
Change this line
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy();
To below mentioned one
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
You can see the working example here for any other issue.
For Reference: https://github.com/Khushbu-2112/OAuth-google-example

How to query using MySQL in an EJS File

I am trying to run a query in a view (.ejs file). However, since the keyword require is not defined in a .ejs file, I need to export it from my main file, server.js.
The whole code for my server.js file is below and this is the specific snippet with which I need help.
app.engine('html', require('ejs').renderFile);
exports.profile = function(req, res) {
res.render('profile', { mysql: mysql });
}
I need to be able to use the mysql.createConnection in my profile.ejs file.
Any help would be great.
// server.js
// set up ======================================================================
// get all the tools we need
var express = require('express');
var app = express();
var port = process.env.PORT || 8080;
var mongoose = require('mongoose');
var passport = require('passport');
var flash = require('connect-flash');
var morgan = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
var configDB = require('./config/database.js');
var Connection = require('tedious').Connection;
var config = {
userName: 'DESKTOP-S6CM9A9\\Yash',
password: '',
server: 'DESKTOP-S6CM9A9\\SQLEXPRESS',
};
var Request = require('tedious').Request;
var TYPES = require('tedious').TYPES;
var mysql = require('mysql');
var con = mysql.createConnection({
host: "localhost",
user: "root",
password: "yashm"
});
con.connect(function(err) {
if (err) throw err;
console.log("Connected!");
var sql="Select * from test.productlist";
con.query(sql, function (err, result) {
if (err) throw err;
console.log(result);
});
});
app.engine('html', require('ejs').renderFile);
exports.profile = function(req, res) {
res.render('profile', { mysql: mysql });
}
//--------------------------------------------------------------------------------
// configuration ===============================================================
mongoose.connect(configDB.url); // connect to our database
require('./config/passport')(passport); // pass passport for configuration
// set up our express application
app.use(morgan('dev')); // log every request to the console
app.use(cookieParser()); // read cookies (needed for auth)
app.use(bodyParser()); // get information from html forms
app.set('view engine', 'ejs'); // set up ejs for templating
// required for passport
app.use(session({ secret: 'test run' })); // session secret
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
app.use(flash()); // use connect-flash for flash messages stored in session
// routes ======================================================================
require('./app/routes.js')(app, passport); // load our routes and pass in our app and fully configured passport
// launch ======================================================================
app.listen(port);
console.log('The magic happens on port ' + port);
Like already said in the comment, you have to do your query logic in your server.js and then pass the data to your view (or maybe even pre-process it!)
exports.profile = function(req, res) {
con.query('SELECT 1', function (error, results, fields) {
if (error) throw error;
// connected!
res.render('profile', { data: results });
});
}
In your ejs you can loop trough the data, and acces the fields as data[i]['fieldname']
<ul>
<% for(var i=0; i<data.length; i++) {%>
<li><%= data[i]['id'] %></li>
<% } %>
</ul>

How to share a session between Express v4 and Socket.io 1.3.2

I've been trying to share an express session to use from socket.io for the past couple of days and I just can't wrap my head around it. I'm using express 4.11.1 with socket.io 1.3.2 (other dependencies are express-session 1.10.1, cookie-parser 1.3.3 and body-parser 1.10.2). I'm basically putting clients data into a session from express and want to use that information in socket.io because sockets loose information on reconnection. What I've done is basically what is done here but it just doesn't work for me.
var express = require('express'),
app = express(),
session = require('express-session'),
cookieParser = require('cookie-parser'),
sessionStore = new session.MemoryStore(),
bodyParser = require('body-parser');
var server = require('http').createServer(app);
var io = require('socket.io')(server);
var port = process.env.PORT || 3000;
var sessionMiddleware = session({
name: 'sid',
store: sessionStore, // MemoryStore
secret: 's3cr37',
saveUninitialized: true,
resave: true,
});
io.use(function(socket, next) {
sessionMiddleware(socket.request, socket.request.res, next);
});
app.use(sessionMiddleware);
app.use(bodyParser.json())
server.listen(port, function() {
console.log('Server listening at port %d', port);
});
app.post('/login', function(req, res){
//just storing the info in session
req.session.username = req.body.user;
...
});
io.on('connection', function(socket) {
//using socket.request.session.username which doesn't work
...
});
Any help would be highly appreciated
So, after a lot of messing with this I figured out how to obtain the value from the session in socket. Instead of accessing the value of a session like this:
socket.request.session.username
I needed to do this:
var getUsernameFromSession = function(socket) {
var sessionId = socket.request.sessionID;
var cookie = JSON.parse(socket.request.sessionStore.sessions[sessionId]);
return cookie.username;
};
I'm not sure how good this is but this works for me.

ExpressJS POST Method Request Issue

I am running into an issue where I am trying to run a POST request via Postman and I get a loading request for a long time and then a Could not get any response message. There are no errors that are appearing in terminal. Is it the way I am saving the POST? Specifically looking at my /blog route.
server.js
//Load express
var express = require('express');
var app = express();
var router = express.Router(); // get an instance of the router
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
// configure app to use bodyParser()
// get data from a POST method
app.use(bodyParser.urlencoded({ extended: true}));
app.use(bodyParser.json());
var port = process.env.PORT || 8080; // set the port
var blogDB = require('./config/blogDB.js');
var Blogpost = require('./app/models/blogModel');
app.set('view engine', 'ejs'); // set ejs as the view engine
app.use(express.static(__dirname + '/public')); // set the public directory
var routes = require('./app/routes');
// use routes.js
app.use(routes);
app.listen(port);
console.log('magic is happening on port' + port);
blogModel.js:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var BlogPostSchema = new Schema({
title : String,
body : String,
date_created : Date
});
module.exports = mongoose.model('Blogpost', BlogPostSchema);
routes.js:
var express = require('express');
var router = express.Router();
var blogDB = require('../config/blogDB.js');
var Blogpost = require('./models/blogModel.js');
//index
router.route('/')
.get(function(req, res) {
var drinks = [
{ name: 'Bloody Mary', drunkness: 3 },
{ name: 'Martini', drunkness: 5 },
{ name: 'Scotch', drunkness: 10}
];
var tagline = "Lets do this.";
res.render('pages/index', {
drinks: drinks,
tagline: tagline
});
});
//blog
router.route('/blog')
.get(function(req, res) {
res.send('This is the blog page');
})
.post(function(req, res) {
var blogpost = new Blogpost(); // create a new instance of a Blogpost model
blogpost.title = req.body.name; // set the blog title
blogpost.body = req.body.body; // set the blog content
blogpost.date_created = Date.now();
blogpost.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'Blog created.' });
});
});
//about
router.get('/about', function(req, res) {
res.render('pages/about');
});
module.exports = router;
The issue was that I did not setup a user for my Mongo database. Basically it couldn't gain access to the user/pw to the database that I was using. Once I created a user matching the user/pw I included in my url, then I was able to get a successful post.

Passport.js Module, undefined callbackURL

After setting up the Drupal as this guide says: Drupal-passport I created a simple simple node app to test how it works.
It doesn't, I get the InternalOAuthError: Failed to obtain request token error.
Going through the strategy.js, I saw that my callbackURL is logging out undefined not exactly sure why. The callbackURL is set in my Drupal app
Also preforming a curl -i -XPOST http://extranet.local/rest/system/connect/ gives me exactly what I need
Here is my node.js code (keep in mind this is just supposed to test the drupal set up).
var express = require('express');
var passport = require('passport');
var dStrategy = require('passport-drupal').DrupalStrategy;
var passportDrupal = require('passport-drupal');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser')
var session = require('express-session');
var http = require('http');
var app = express();
var server = http.createServer(app);
app.use(cookieParser());
app.use(bodyParser());
app.use(session({ secret: 'SECRET' }));
app.use(passport.initialize());
app.use(passport.session());
passport.use(new dStrategy({
consumerKey: "emDVp7P2LZFLPcN3cNCjLmrjrhQLnNv6",
consumerSecret: "mkbc3UYEuUQLNQRwLWo3B8zEk4ZrErKa",
providerURL: "http://extranet.local",
resourceEndpoint: "rest/system/connect", // <---- optional. Defaults to `rest/system/connect`
callbackURL: 'http://33.33.33.40:8888/auth/drupal/callback'
},
function(token, tokenSecret, profile, done) {
profile.oauth = { token: token, token_secret: tokenSecret };
done(null, profile);
}
));
app.get('/', function(req, res) {
res.writeHead(200);
res.end("This is root");
});
app.get('/auth/drupal',
passport.authenticate('drupal'),
function(req, res) {
// The request will be redirected to the Drupal website for
// authentication, so this function will not be called.
});
app.get('/auth/drupal/callback',
passport.authenticate('drupal', { failureRedirect: '/error' }),
function(req, res) {
// Successful authentication, redirect home.
res.redirect('/signedin');
});
app.get('/error', function(req, res) {
res.writeHead(200);
res.end("Could not sign in");
});
app.get('/signedin', function(req, res) {
res.writeHead(200);
res.end("signed in");
});
server.listen(8888, '33.33.33.40');
Any clues as to why or ideas are greatly appreciated
If you look into the strategy.js code of the library passport-drupal, you will see that the DrupalStrategy constructor does not expect a callbackURL property in the options parameter object and it also does not pass it further into the OAuthStrategy.
This is the code snippet that creates the parameter for the oauth strategy:
// Determine all necessary OAuth options
var oauthOptions = {
requestTokenURL: this._providerURL + '/oauth/request_token',
accessTokenURL: this._providerURL + '/oauth/access_token',
userAuthorizationURL: this._providerURL + '/oauth/authorize',
consumerKey: options.consumerKey,
consumerSecret: options.consumerSecret
};
OAuthStrategy.call(this, oauthOptions, verify);
It should be modified to pass the callbackURL, for example like this:
// Determine all necessary OAuth options
var oauthOptions = {
requestTokenURL: this._providerURL + '/oauth/request_token',
accessTokenURL: this._providerURL + '/oauth/access_token',
userAuthorizationURL: this._providerURL + '/oauth/authorize',
consumerKey: options.consumerKey,
consumerSecret: options.consumerSecret,
callbackURL: options.callbackURL// <==== THIS LINE WAS ADDED
};
OAuthStrategy.call(this, oauthOptions, verify);
I'm not sure that will solve your issue though. But I made a pull request

Categories

Resources