1
0
mirror of https://github.com/dani/vroom.git synced 2024-07-02 12:13:12 +02:00
vroom/signalmaster/server.js

186 lines
5.9 KiB
JavaScript
Raw Normal View History

2014-04-03 17:42:54 +02:00
/*global console*/
var config = require('getconfig'),
uuid = require('node-uuid'),
mysql = require('mysql'),
cookie_reader = require('cookie'),
2014-05-30 12:01:34 +02:00
crypto = require('crypto'),
port = parseInt(process.env.PORT || config.server.port, 10),
io = require('socket.io').listen(port);
2014-04-03 17:42:54 +02:00
var sql = mysql.createConnection({
host : config.mysql.server,
database : config.mysql.database,
user : config.mysql.user,
password : config.mysql.password});
2014-05-30 12:01:34 +02:00
if (config.logLevel) {
// https://github.com/Automattic/socket.io/wiki/Configuring-Socket.IO
io.set('log level', config.logLevel);
}
2014-04-03 17:42:54 +02:00
function describeRoom(name) {
var clients = io.sockets.clients(name);
var result = {
clients: {}
};
clients.forEach(function (client) {
result.clients[client.id] = client.resources;
});
return result;
}
function safeCb(cb) {
if (typeof cb === 'function') {
return cb;
} else {
return function () {};
}
}
function checkRoom(room,token,user) {
var q = "SELECT participant FROM participants WHERE participant='" + user + "' AND id IN (SELECT id FROM rooms WHERE name='" + room + "' AND token='" + token + "');";
console.log('Checking if ' + user + ' is allowed to join room ' + room + ' using token ' + token);
sql.query(q, function(err, rows, fields) {
if (err) throw err;
// No result ? This user hasn't joined this room through our frontend
if (rows.length < 1) return false;
});
return true;
}
io.configure(function(){
io.set('close timeout', 20);
io.set('heartbeat timeout', 10);
io.set('heartbeat interval', 5);
2014-04-03 17:42:54 +02:00
io.set('authorization', function(data, accept){
if(data.headers.cookie){
data.cookie = cookie_reader.parse(data.headers.cookie);
var session = data.cookie['vroomsession'];
if (typeof session != 'string'){
2014-05-15 16:57:05 +02:00
console.log('Cookie vroomsession not found, access unauthorized');
2014-04-03 17:42:54 +02:00
return ('error', false);
}
// vroomsession is base64(user:room:token) so let's decode this !
session = new Buffer(session, encoding='base64');
var tab = session.toString().split(':');
var user = tab[0],
room = tab[1],
token = tab[2];
// sanitize user input, we don't want to pass random junk to MySQL do we ?
if (!user.match(/^[\w\@\.\-]{1,40}$/i) || !room.match(/^[\w\-]{1,50}$/) || !token.match(/^[a-zA-Z0-9]{50}$/)){
console.log('Forbidden chars found in either participant session, room name or token, sorry, cannot allow this');
return ('error', false);
}
// Ok, now check if this user has joined the room (with the correct token) through vroom frontend
if (checkRoom(room,token,user) == false){
console.log('Sorry, but ' + participant + ' is not allowed to join room ' + name);
return ('error', false);
}
return accept(null, true);
}
console.log('No cookies were found, access unauthorized');
return accept('error', false);
});
});
io.sockets.on('connection', function (client) {
client.resources = {
screen: false,
video: true,
audio: false
};
// pass a message to another id
client.on('message', function (details) {
var otherClient = io.sockets.sockets[details.to];
if (!otherClient) return;
details.from = client.id;
otherClient.emit('message', details);
});
client.on('shareScreen', function () {
client.resources.screen = true;
});
client.on('unshareScreen', function (type) {
client.resources.screen = false;
2014-05-30 12:01:34 +02:00
removeFeed('screen');
2014-04-03 17:42:54 +02:00
});
client.on('join', join);
function removeFeed(type) {
2014-05-30 12:01:34 +02:00
if (client.room) {
io.sockets.in(client.room).emit('remove', {
id: client.id,
type: type
});
if (!type) {
client.leave(client.room);
client.room = undefined;
}
}
2014-04-03 17:42:54 +02:00
}
function join(name, cb) {
// sanity check
if (typeof name !== 'string') return;
// leave any existing rooms
2014-05-30 12:01:34 +02:00
removeFeed();
safeCb(cb)(null, describeRoom(name));
2014-04-03 17:42:54 +02:00
client.join(name);
client.room = name;
}
// we don't want to pass "leave" directly because the
// event type string of "socket end" gets passed too.
client.on('disconnect', function () {
removeFeed();
});
2014-05-30 12:01:34 +02:00
client.on('leave', function () {
removeFeed();
});
2014-04-03 17:42:54 +02:00
client.on('create', function (name, cb) {
if (arguments.length == 2) {
cb = (typeof cb == 'function') ? cb : function () {};
name = name || uuid();
} else {
cb = name;
name = uuid();
}
// check if exists
if (io.sockets.clients(name).length) {
safeCb(cb)('taken');
} else {
join(name);
safeCb(cb)(null, name);
}
});
2014-05-30 12:01:34 +02:00
// tell client about stun and turn servers and generate nonces
if (config.stunservers) {
client.emit('stunservers', config.stunservers);
}
if (config.turnservers) {
// create shared secret nonces for TURN authentication
// the process is described in draft-uberti-behave-turn-rest
var credentials = [];
config.turnservers.forEach(function (server) {
var hmac = crypto.createHmac('sha1', server.secret);
// default to 86400 seconds timeout unless specified
var username = Math.floor(new Date().getTime() / 1000) + (server.expiry || 86400) + "";
hmac.update(username);
credentials.push({
username: username,
credential: hmac.digest('base64'),
url: server.url
});
});
client.emit('turnservers', credentials);
}
2014-04-03 17:42:54 +02:00
});
if (config.uid) process.setuid(config.uid);
2014-05-30 12:01:34 +02:00
console.log('signal master is running at: http://localhost:' + port);