Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

98 lines
3.0 KiB

4 years ago
'use strict';
var _ = require('lodash');
var debug = require('debug')('socketio-auth');
/**
* Adds connection listeners to the given socket.io server, so clients
* are forced to authenticate before they can receive events.
*
* @param {Object} io - the socket.io server socket
*
* @param {Object} config - configuration values
* @param {Function} config.authenticate - indicates if authentication was successfull
* @param {Function} config.postAuthenticate=noop - called after the client is authenticated
* @param {Function} config.disconnect=noop - called after the client is disconnected
* @param {Number} [config.timeout=1000] - amount of millisenconds to wait for a client to
* authenticate before disconnecting it. A value of 'none' means no connection timeout.
*/
module.exports = function socketIOAuth(io, config) {
config = config || {};
var timeout = config.timeout || 1000;
var postAuthenticate = config.postAuthenticate || _.noop;
var disconnect = config.disconnect || _.noop;
_.each(io.nsps, forbidConnections);
io.on('connection', function(socket) {
socket.auth = false;
socket.on('authentication', function(data) {
config.authenticate(socket, data, function(err, success) {
if (success) {
debug('Authenticated socket %s', socket.id);
socket.auth = true;
_.each(io.nsps, function(nsp) {
restoreConnection(nsp, socket);
});
socket.emit('authenticated', success);
return postAuthenticate(socket, data);
} else if (err) {
debug('Authentication error socket %s: %s', socket.id, err.message);
socket.emit('unauthorized', {message: err.message}, function() {
socket.disconnect();
});
} else {
debug('Authentication failure socket %s', socket.id);
socket.emit('unauthorized', {message: 'Authentication failure'}, function() {
socket.disconnect();
});
}
});
});
socket.on('disconnect', function() {
return disconnect(socket);
});
if (timeout !== 'none') {
setTimeout(function() {
// If the socket didn't authenticate after connection, disconnect it
if (!socket.auth) {
debug('Disconnecting socket %s', socket.id);
socket.disconnect('unauthorized');
}
}, timeout);
}
});
};
/**
* Set a listener so connections from unauthenticated sockets are not
* considered when emitting to the namespace. The connections will be
* restored after authentication succeeds.
*/
function forbidConnections(nsp) {
nsp.on('connect', function(socket) {
if (!socket.auth) {
debug('removing socket from %s', nsp.name);
delete nsp.connected[socket.id];
}
});
}
/**
* If the socket attempted a connection before authentication, restore it.
*/
function restoreConnection(nsp, socket) {
if (_.find(nsp.sockets, {id: socket.id})) {
debug('restoring socket to %s', nsp.name);
nsp.connected[socket.id] = socket;
}
}