'use strict'; // Load the module dependencies var config = require('../config'), path = require('path'), fs = require('fs'), http = require('http'), https = require('https'), cookieParser = require('cookie-parser'), passport = require('passport'), socketio = require('socket.io'), moment = require('moment'), session = require('express-session'), MongoStore = require('connect-mongo')(session); // Define the Socket.io configuration method module.exports = function (app, db) { var server; if (config.secure && config.secure.ssl === true) { // Load SSL key and certificate var privateKey = fs.readFileSync(path.resolve(config.secure.privateKey), 'utf8'); var certificate = fs.readFileSync(path.resolve(config.secure.certificate), 'utf8'); var caBundle; try { caBundle = fs.readFileSync(path.resolve(config.secure.caBundle), 'utf8'); } catch (err) { console.log('Warning: couldn\'t find or read caBundle file'); } var options = { key: privateKey, cert: certificate, ca: caBundle, // requestCert : true, // rejectUnauthorized : true, secureProtocol: 'TLSv1_method', ciphers: [ 'ECDHE-RSA-AES128-GCM-SHA256', 'ECDHE-ECDSA-AES128-GCM-SHA256', 'ECDHE-RSA-AES256-GCM-SHA384', 'ECDHE-ECDSA-AES256-GCM-SHA384', 'DHE-RSA-AES128-GCM-SHA256', 'ECDHE-RSA-AES128-SHA256', 'DHE-RSA-AES128-SHA256', 'ECDHE-RSA-AES256-SHA384', 'DHE-RSA-AES256-SHA384', 'ECDHE-RSA-AES256-SHA256', 'DHE-RSA-AES256-SHA256', 'HIGH', '!aNULL', '!eNULL', '!EXPORT', '!DES', '!RC4', '!MD5', '!PSK', '!SRP', '!CAMELLIA' ].join(':'), honorCipherOrder: true }; // Create new HTTPS Server server = https.createServer(options, app); } else { // Create a new HTTP server server = http.createServer(app); } // Create a new Socket.io server var io = socketio.listen(server); io.chatClients = []; io.banClients = []; // Create a MongoDB storage object var mongoStore = new MongoStore({ mongooseConnection: db.connection, collection: config.sessionCollection }); // Intercept Socket.io's handshake request io.use(function (socket, next) { // Use the 'cookie-parser' module to parse the request cookies cookieParser(config.sessionSecret)(socket.request, {}, function (err) { // Get the session id from the request cookies var sessionId = socket.request.signedCookies ? socket.request.signedCookies[config.sessionKey] : undefined; if (!sessionId) return next(new Error('sessionId was not found in socket.request'), false); // Use the mongoStorage instance to get the Express session information mongoStore.get(sessionId, function (err, session) { if (err) return next(err, false); if (!session) return next(new Error('session was not found for ' + sessionId), false); // Set the Socket.io session information socket.request.session = session; // Use Passport to populate the user details passport.initialize()(socket.request, {}, function () { passport.session()(socket.request, {}, function () { if (socket.request.user) { var logined = false; var banned = false; //init user initUser(socket.request.user); // check user already login io.chatClients.forEach(function (s) { if (s.request.user.username === socket.request.user.username) { logined = true; next(new Error('username "' + socket.request.user.username + '" already login from other location'), false); } }); // check ban list if (!logined) { for (var i = io.banClients.length - 1; i >= 0; i--) { var buser = io.banClients[i]; if (buser.expires <= Date.now()) { //already expires, remove it io.banClients.splice(io.banClients.indexOf(buser), 1); continue; } else { var address = socket.handshake.address; if (buser.user.username === socket.request.user.username) { //username in ban list banned = true; next(new Error('username "' + buser.user.username + '" is banned from the server'), false); } else if (buser.ip === address) { //ip in ban list banned = true; next(new Error('ip "' + buser.ip + '" is banned from the server'), false); } } } } if (!logined && !banned) { next(null, true); } } else { next(new Error('User is not authenticated'), false); } }); }); }); }); }); // init user isOper/isAdmin/isVip function initUser(user) { user.isVip = false; if (!user.vip_start_at || !user.vip_end_at) { user.isVip = false; } else if (moment(Date.now()) > moment(user.vip_end_at)) { user.isVip = false; } else { user.isVip = true; } user.isOper = (user.roles[0] === 'oper' || user.roles[0] === 'admin'); user.isAdmin = (user.roles[0] === 'admin'); } // Add an event listener to the 'connection' event io.on('connection', function (socket) { config.files.server.sockets.forEach(function (socketConfiguration) { require(path.resolve(socketConfiguration))(io, socket); }); }); return server; };