From c1186f396eb2d0e5f6c8eb5e7a06b1d5579b53f6 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 24 Apr 2013 16:42:12 -0400 Subject: [PATCH] some work on session login etc --- package.json | 3 ++- public/src/app.js | 4 ++-- src/redis.js | 7 ++++++- src/templates.js | 6 +++++- src/user.js | 24 +++++++++--------------- src/webserver.js | 34 ++++++++++++++++++++++++---------- src/websockets.js | 29 ++++++++++++++++++++++++++--- 7 files changed, 74 insertions(+), 33 deletions(-) diff --git a/package.json b/package.json index 0a87afb1a6..04ae2eb43b 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ "redis": "0.8.3", "express": "3.2.0", "connect": "2.7.6", - "emailjs": "0.3.4" + "emailjs": "0.3.4", + "cookie": "0.0.6" }, "devDependencies": {}, "optionalDependencies": {}, diff --git a/public/src/app.js b/public/src/app.js index e6363b710b..8f57fa18db 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -10,8 +10,8 @@ var socket, config = data; socket = io.connect('http://' + config.socket.address + config.socket.port? ':' + config.socket.port : ''); - socket.on('event:connect', function(data) { - + socket.on('connect', function(data) { + console.log('connected to socket.io: ', data); }); socket.on('event:alert', function(data) { diff --git a/src/redis.js b/src/redis.js index 65827da2e2..1582fb0f03 100644 --- a/src/redis.js +++ b/src/redis.js @@ -22,8 +22,9 @@ } } - RedisDB.set = function(key, value) { + RedisDB.set = function(key, value, expiry) { db.set(key, value); + if (expiry !== undefined) RedisDB.expire(key, expiry); }; RedisDB.get = function(key, callback, error_handler) { @@ -36,6 +37,10 @@ db.del(key); } + RedisDB.expire = function(key, expiry) { + db.expire(key, expiry); + } + // Atomic Operations RedisDB.incr = function(key, callback, error_handler) { db.incr(key, function(error, data) { diff --git a/src/templates.js b/src/templates.js index e211d75403..73766a33c0 100644 --- a/src/templates.js +++ b/src/templates.js @@ -24,7 +24,11 @@ var fs = require('fs'); } Templates.init = function() { - loadTemplates(['header', 'footer', 'register', 'home', 'login', 'reset', 'reset_code', 'emails/reset', 'emails/reset_plaintext']); + loadTemplates([ + 'header', 'footer', 'register', 'home', + 'login', 'reset', 'reset_code', 'account_settings', + 'emails/reset', 'emails/reset_plaintext' + ]); } var parse = function(data) { diff --git a/src/user.js b/src/user.js index 2c621e1582..76c09adccb 100644 --- a/src/user.js +++ b/src/user.js @@ -5,44 +5,38 @@ var config = require('../config.js'), emailjsServer = emailjs.server.connect(config.mailer); (function(User) { - var current_uid; User.login = function(user) { - if (current_uid) { - return global.socket.emit('user.login', {'status': 0, 'message': 'User is already logged in.'}); - - } - if (user.username == null || user.password == null) { return global.socket.emit('user.login', {'status': 0, 'message': 'Missing fields'}); - } RDB.get('username:' + user.username + ':uid', function(uid) { if (uid == null) { return global.socket.emit('user.login', {'status': 0, 'message': 'Username does not exist.'}); - } RDB.get('uid:' + uid + ':password', function(password) { if (user.password != password) { return global.socket.emit('user.login', {'status': 0, 'message': 'Incorrect username / password combination.'}); } else { + // Start, replace, or extend a session + RDB.get('uid:' + uid + ':session', function(session) { + if (session !== user.sessionID) { + RDB.set('uid:' + uid + ':session', user.sessionID, 60*60*24*14); // Login valid for two weeks + } else { + RDB.expire('uid:' + uid + ':session', 60*60*24*14); // Defer expiration to two weeks from now + } + }); + return global.socket.emit('user.login', {'status': 1, 'message': 'Logged in!'}); } }); - }); - - }; User.create = function(username, password, email) { - if (current_uid) { - return; global.socket.emit('user.create', {'status': 0, 'message': 'Only anonymous users can register a new account.'}); - } - if (username == null || password == null) { return; global.socket.emit('user.create', {'status': 0, 'message': 'Missing fields'}); } diff --git a/src/webserver.js b/src/webserver.js index 44d6203c6d..d3fff55b45 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -14,6 +14,25 @@ var express = require('express'), modules.templates.init(); } } + + function checkAuth(req, res, next) { + if (!req.session || !req.session.uid) { + res.send(403, 'You are not authorized to view this page'); + } else { + next(); + } + } + + // Middlewares + app.use(express.favicon()); // 2 args: string path and object options (i.e. expire time etc) + app.use(express.bodyParser()); // Puts POST vars in request.body + app.use(express.cookieParser()); // If you want to parse cookies (res.cookies) + app.use(express.session({secret: 'nodebb-julian', key: 'express.sid'})); + // Dunno wtf this does + // app.use(express.logger({ format: '\x1b[1m:method\x1b[0m \x1b[33m:url\x1b[0m :response-time ms' })); + // Useful if you want to use app.put and app.delete (instead of app.post all the time) + // app.use(express.methodOverride()); + app.get('/', function(req, res) { refreshTemplates(); res.send(templates['header'] + templates['home'] + templates['footer']); @@ -39,22 +58,17 @@ var express = require('express'), res.send(templates['header'] + templates['register'] + templates['footer']); }); + app.get('/account', checkAuth, function(req, res) { + refreshTemplates(); + res.send(templates['header'] + templates['account_settings'] + templates['footer']); + }); + module.exports.init = function() { // todo move some of this stuff into config.json app.configure(function() { - app.use(express.favicon()); // 2 args: string path and object options (i.e. expire time etc) - app.use(express.bodyParser()); // Puts POST vars in request.body - app.use(express.cookieParser()); // Presumably important - - // Dunno wtf this does - // app.use(express.logger({ format: '\x1b[1m:method\x1b[0m \x1b[33m:url\x1b[0m :response-time ms' })); - - // Useful if you want to use app.put and app.delete (instead of app.post all the time) - // app.use(express.methodOverride()); app.use(express.static(global.configuration.ROOT_DIRECTORY + '/public')); }); } - }(WebServer)); server.listen(config.port); diff --git a/src/websockets.js b/src/websockets.js index d88a4cdff7..3a12c2df3f 100644 --- a/src/websockets.js +++ b/src/websockets.js @@ -1,13 +1,34 @@ -var SocketIO = require('socket.io').listen(global.server); +var SocketIO = require('socket.io').listen(global.server), + cookie = require('cookie'), + connect = require('connect'); (function(io) { - var modules = null; + var modules = null, + sessionID; global.io = io; module.exports.init = function() { modules = global.modules; } + // Adapted from http://howtonode.org/socket-io-auth + io.set('authorization', function(handshakeData, accept) { + if (handshakeData.headers.cookie) { + handshakeData.cookie = cookie.parse(handshakeData.headers.cookie); + handshakeData.sessionID = connect.utils.parseSignedCookie(handshakeData.cookie['express.sid'], 'nodebb-julian'); + + if (handshakeData.cookie['express.sid'] == handshakeData.sessionID) { + return accept('Cookie is invalid.', false); + } + } else { + // No cookie sent + return accept('No cookie transmitted', false); + } + + // Otherwise, continue unimpeded. + sessionID = handshakeData.sessionID; + accept(null, true); + }); io.sockets.on('connection', function(socket) { global.socket = socket; @@ -17,7 +38,8 @@ var SocketIO = require('socket.io').listen(global.server); modules.templates.init(); } - socket.emit('event:connect', {status: 1}); + // not required, "connect" emitted automatically + // socket.emit('event:connect', {status: 1}); // BEGIN: API calls (todo: organize) // julian: :^) @@ -38,6 +60,7 @@ var SocketIO = require('socket.io').listen(global.server); }); socket.on('user.login', function(data) { + data.sessionID = sessionID; modules.user.login(data); });