diff --git a/app.json b/app.json index 5ee0d35..1fa4504 100644 --- a/app.json +++ b/app.json @@ -3,9 +3,13 @@ "description": "Client side (E2EE) encrypted instant chat", "keywords": [ "cryptalk", - "encrypted", - "chat", - "e2ee" + "fandango", + "crypto-js", + "AES", + "secure", + "html5", + "encryption", + "privacy" ], "repository": "https://github.com/Hexagon/cryptalk" } \ No newline at end of file diff --git a/package.json b/package.json index c0068e3..88fbeef 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "cryptalk", - "version" : "1.0.7", + "version" : "1.1.0", "description" : "Encrypted HTML5/Node.JS instant chat", "main" : "server.js", "subdomain": "cryptalk", @@ -13,7 +13,9 @@ "crypto-js", "AES", "secure", - "html5" + "html5", + "encryption", + "privacy" ], "author": "Hexagon ", "contributors": [{ @@ -27,7 +29,8 @@ }, "bin" : "./server.js", "dependencies": { - "express.io": ">= 1.1.13" + "express": "4.13.3", + "socket.io": "1.3.7" }, "os": [ "darwin", diff --git a/public/js/bootstrap.js b/public/js/bootstrap.js index b0d8d10..c867694 100644 --- a/public/js/bootstrap.js +++ b/public/js/bootstrap.js @@ -2,15 +2,13 @@ // Setup fandango fandango.defaults({ + baseUrl: 'js/cryptalk_modules/', + paths: { - websocket: 'https://cdnjs.cloudflare.com/ajax/libs/socket.io/0.9.16/socket.io.min.js', - // Newer version: - // We'll have to fix the Access Control issue first though (https://github.com/Automattic/socket.io-client/issues/641). - // websocket: 'https://cdn.socket.io/socket.io-1.1.0.js', + websocket: '/socket.io/socket.io.js', aes: 'https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js', - SHA1: 'https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/sha1.js', - domReady: 'https://cdnjs.cloudflare.com/ajax/libs/require-domReady/2.0.1/domReady.min.js' + SHA1: 'https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/sha1.js' }, // CryptoJs AES does not support AMD modules. We'll have to create a shim. diff --git a/public/js/cryptalk_modules/$.js b/public/js/cryptalk_modules/$.js index 6add817..aa1331a 100644 --- a/public/js/cryptalk_modules/$.js +++ b/public/js/cryptalk_modules/$.js @@ -1,4 +1,5 @@ define(['fandango', 'websocket', 'aes', 'SHA1'], function (fandango, websocket, aes, SHA1) { + var exports = { selector: 0, utilities: {}, @@ -56,10 +57,7 @@ define(['fandango', 'websocket', 'aes', 'SHA1'], function (fandango, websocket, }; // Namespace websocket - utils.Websocket = { - connect: websocket.connect, - on: websocket.on - }; + utils.io = websocket; utils.ssplit = function (string, seperator) { var components = string.split(seperator); @@ -144,14 +142,13 @@ define(['fandango', 'websocket', 'aes', 'SHA1'], function (fandango, websocket, each(this, function (element) { element.innerHTML = string; }); - return this; }; proto.append = function (string) { - for (var i = 0, len = this.length; i < len; i++) { - this[0].innerHTML += string; - } + each(this, function (element) { + element.innerHTML += string; + }); return this; }; @@ -161,20 +158,21 @@ define(['fandango', 'websocket', 'aes', 'SHA1'], function (fandango, websocket, // Naive implementations of .on() proto.on = function (eventName, callback) { - for (var i = 0, len = this.length; i < len; i++) { - if (this[0].addEventListener) { - this[0].addEventListener(eventName, callback, false); - } else if (this[0].attachEvent) { - this[0].attachEvent('on' + eventName, callback); + each(this, function (element) { + if (element.addEventListener) { + element.addEventListener(eventName, callback, false); + } else if (element.attachEvent) { + element.attachEvent('on' + eventName, callback); } - } - + }); return this; }; proto.focus = function () { - this[0].focus(); - + // It doesn't make sense to focus all matched elements. So we settle for the first one + if(this[0]) { + this[0].focus(); + } return this; }; diff --git a/public/js/cryptalk_modules/host.js b/public/js/cryptalk_modules/host.js index ced1c3a..8a8851d 100644 --- a/public/js/cryptalk_modules/host.js +++ b/public/js/cryptalk_modules/host.js @@ -116,7 +116,7 @@ define( } else if (fandango.is(toHost, 'untyped')) { settings = toHost.settings; } else { // Assume string - request = toHost; + request = toHost.settings; } if (request) { @@ -137,7 +137,7 @@ define( mediator.emit('console:motd', host.settings.motd); // The one and only socket - socket = $.Websocket.connect(host.host, { + socket = $.io(host.host, { forceNew: true, 'force new connection': true }); @@ -187,6 +187,7 @@ define( }) .on('connect', function () { + // Tell the user that the chat is ready to interact with mediator.emit('console:info', $.template(templates.messages.connected, { host: host.name || 'localhost' @@ -204,6 +205,7 @@ define( }) .on('disconnect', function () { + room = 0; key = 0; host.connected = 0; @@ -218,7 +220,8 @@ define( mediator.emit('window:title',templates.client.title); }) - .on('error', function () { + .on('connect_error', function () { + room = 0; key = 0; host.connected = 0; diff --git a/public/js/cryptalk_modules/hosts.js b/public/js/cryptalk_modules/hosts.js index 59dc995..18c1fdb 100644 --- a/public/js/cryptalk_modules/hosts.js +++ b/public/js/cryptalk_modules/hosts.js @@ -8,7 +8,7 @@ define({ hosts: [ { name: 'default', - host: '', + host: 'localhost:8080', path: '/js/cryptalk_modules/settings.js' }/*, { diff --git a/public/js/cryptalk_modules/window.js b/public/js/cryptalk_modules/window.js index 02e0984..150f9fb 100644 --- a/public/js/cryptalk_modules/window.js +++ b/public/js/cryptalk_modules/window.js @@ -12,7 +12,7 @@ */ define(['castrato'],function (mediator){ - + var exports = {}, focusCallback = function() { @@ -26,6 +26,7 @@ define(['castrato'],function (mediator){ exports.setTitle = function(t) { document.title = t; }, exports.getTitle = function() { return document.title; }; + // Keep track of document focus/blur if (window.addEventListener){ // Normal browsers diff --git a/server.js b/server.js index f012419..054efe2 100644 --- a/server.js +++ b/server.js @@ -1,89 +1,88 @@ #!/usr/bin/env node +var express = require('express'), + app = express(), + server = require('http').createServer(app), + io = require('socket.io')(server), + port = process.env.PORT || 8080; -var express = require('express.io'), - app = express();app.http().io(); - -app.use(express.static(__dirname + '/public')); - -app.io.route('room', { - join: function(req) { - if( req.data ) { - req.socket.emit('room:joined',req.data); - req.socket.join(req.data); - req.socket.broadcast.to(req.data).emit('message:server', {msg:'person_joined'} ); - req.socket.current_room = req.data; - } else { - req.socket.emit('message:server', {msg:'command_failed'} ); - } - }, - leave: function(req) { - if( req.data ) { - req.socket.emit('room:left'); - req.socket.leave(req.data); - req.socket.broadcast.to(req.data).emit('message:server', {msg:'person_left'} ); - req.socket.current_room = undefined; - } else { - req.socket.emit('message:server', {msg:'command_failed'} ); - } - }, - count: function(req) { - if( req.socket.current_room !== undefined ) { - // This will fail on socket.io >= 1.0 - var client_count = app.io.sockets.clients(req.socket.current_room).length; - req.socket.emit('message:server', {msg:'person_count', payload: client_count } ); - } else { - req.socket.emit('message:server', {msg:'command_failed'} ); - } - } +server.listen(port, function(){ + console.log('listening on *:'+port); }); -app.io.route('message', { - send: function(req) { +// Serve /public/* as / +app.use(express.static(__dirname + '/public')); - // Check that the user is in a room - if(req.data && req.data.room) { +io.on('connection', function(socket) { - // Check that the message size is within bounds - var total_msg_size = (req.data.msg) ? req.data.msg.length : 0 + (req.data.nick) ? req.data.nick.length : 0; - if( total_msg_size <= 4096) { + socket.on('room:join', function(req) { + if( req ) { + socket.emit('room:joined',req); + socket.join(req); + socket.broadcast.to(req).emit('message:server', {msg:'person_joined'} ); + socket.current_room = req; + } else { + socket.emit('message:server', {msg:'command_failed'} ); + } + }); - // Check that at least 100ms has passed since last message - if( req.socket.last_message === undefined || new Date().getTime() - req.socket.last_message > 100 ) { + socket.on('room:leave', function(req) { + if( req ) { + socket.emit('room:left'); + socket.leave(req); + socket.broadcast.to(req).emit('message:server', {msg:'person_left'} ); + socket.current_room = undefined; + } else { + socket.emit('message:server', {msg:'command_failed'} ); + } + }); - req.socket.broadcast.to(req.data.room).emit('message:send', { msg: req.data.msg, nick: req.data.nick} ); - req.socket.emit('message:send', { msg: req.data.msg, nick: req.data.nick} ); + socket.on('room:count', function (req) { + if( socket.current_room !== undefined ) { + var clientsList = io.sockets.adapter.rooms[socket.current_room]; + socket.emit('message:server', {msg:'person_count', payload: Object.keys(clientsList).length } ); + } else { + socket.emit('message:server', {msg:'command_failed'} ); + } + }); - req.socket.last_message = new Date().getTime(); + socket.on('message:send', function(req) { + + // Check that the user is in a room + if(req && req.room) { + + // Check that the message size is within bounds + var total_msg_size = (req.msg) ? req.msg.length : 0 + (req.nick) ? req.nick.length : 0; + if( total_msg_size <= 4096) { + + // Check that at least 100ms has passed since last message + if( socket.last_message === undefined || new Date().getTime() - socket.last_message > 100 ) { + + socket.broadcast.to(req.room).emit('message:send', { msg: req.msg, nick: req.nick} ); + socket.emit('message:send', { msg: req.msg, nick: req.nick} ); + + socket.last_message = new Date().getTime(); + + } else { + + // Do not complain if message rate is too fast, that would only generate more traffic + + } } else { - // Do not complain if message rate is too fast, that would only generate more traffic - + // Message size is out of bounds, complain + socket.emit('message:server', {msg:'command_failed'} ); } - } else { + } - // Message size is out of bounds, complain - req.socket.emit('message:server', {msg:'command_failed'} ); - } - - } + }); + socket.on('disconnect', function() { + // Notify other users of the room + if( socket.current_room !== undefined ) { + socket.broadcast.to(socket.current_room).emit('message:server', {msg:'person_left'} ); } + }); }); - -app.io.sockets.on('connection', function(socket) { - socket.on('disconnect', function() { - // Notify other users of the room - if( socket.current_room !== undefined ) { - socket.broadcast.to(socket.current_room).emit('message:server', {msg:'person_left'} ); - } - }); -}); - -var port = process.env.PORT || 8080; - -app.listen(port, function(){ - console.log('listening on *:'+port); -});