cryptalk/public/js/cryptalk_modules/cryptalk.js

259 lines
6.8 KiB
JavaScript
Raw Normal View History

2014-09-18 12:21:07 -04:00
// Main cryptalk module. Will be called by bootstrap.js when the DOM is ready to interact with.
define('cryptalk', {
data: {
// If no host is given it will default to localhost.
2014-09-18 13:19:44 -04:00
host: ''
2014-09-18 12:21:07 -04:00
},
compiles: ['$'],
2014-09-20 09:26:43 -04:00
requires: ['templates','sound']
2014-09-18 12:21:07 -04:00
}, function ($, requires, data) {
var socket,
key,
room,
hash,
2014-09-18 13:17:41 -04:00
nick,
2014-09-20 09:26:43 -04:00
mute = false,
2014-09-18 12:21:07 -04:00
// Collection of DOM components
components = {
chat: $('#chat'),
input: $('#input')
},
// Shortcut
2014-09-20 09:26:43 -04:00
templates = requires.templates;
sound = requires.sound;
2014-09-18 12:21:07 -04:00
// Adds a new message to the DOM
2014-09-18 13:17:41 -04:00
post = function (type, text, clearChat, clearBuffer, nick) {
2014-09-18 12:21:07 -04:00
var tpl = templates.post[type],
post = $.template(tpl, text && {
2014-09-18 13:17:41 -04:00
text: text,
nick: nick
2014-09-18 12:21:07 -04:00
});
// Always clear the input after a post
if (clearBuffer) {
components.input[0].value = '';
}
// Append the post to the chat DOM element
components.chat[clearChat ? 'html' : 'append'](post);
},
// Chat related commands
commands = {
help: function () {
2014-09-18 15:38:15 -04:00
post('motd', templates.help);
2014-09-18 12:21:07 -04:00
},
clear: function () {
components.chat.html('');
},
leave: function () {
2014-09-18 13:17:41 -04:00
if( room ) {
socket.emit('room:leave', room);
} else {
post('error', templates.messages.leave_from_nowhere);
}
2014-09-18 12:21:07 -04:00
},
2014-09-19 13:25:16 -04:00
count: function () {
if( room ) {
socket.emit('room:count');
} else {
post('error', templates.messages.not_in_room);
}
},
2014-09-18 12:21:07 -04:00
key: function (payload) {
// Make sure the key meets the length requirements
if (payload.length < 8) {
2014-09-18 13:17:41 -04:00
return post('error', templates.messages.key_weak);
2014-09-18 12:21:07 -04:00
}
// Set key
key = payload;
// Inform that the key has been set
post('info', (room ? templates.messages.key_ok_ready : templates.messages.key_ok_but_no_room));
},
2014-09-18 13:17:41 -04:00
nick: function (payload) {
// Make sure the nick meets the length requirements
if (payload.length < 2) {
return post('error', templates.messages.nick_short);
}
// Set nick
nick = payload;
// Inform that the key has been set
post('info', $.template(templates.messages.nick_set, { nick: nick}));
},
2014-09-20 09:26:43 -04:00
mute: function () {
// Set nick
mute = !mute;
// Inform that the key has been set
if( mute )
post('info', $.template(templates.messages.muted ));
else
post('info', $.template(templates.messages.unmuted ));
},
2014-09-18 12:21:07 -04:00
join: function (payload) {
return (
room
2014-09-18 13:17:41 -04:00
? post('error', $.template(templates.messages.already_in_room, { roomName: room}))
2014-09-18 12:21:07 -04:00
: socket.emit('room:join', payload)
);
},
2014-09-18 13:17:41 -04:00
generate: function (payload) {
return (
room
? post('error', $.template(templates.messages.already_in_room, { roomName: room}))
: socket.emit('room:generate')
);
2014-09-18 12:21:07 -04:00
}
},
// Handler for the document`s keyDown-event.
onKeyDown = function (e) {
var buffer,
parts,
payload,
command;
// The Document object is bound to this element.
// If the active element is not the input, focus on it and exit the function.
if (components.input[0] !== $.activeElement()) {
return components.input.focus();
}
// Return immediatly if the buffer is empty or if the hit key was not <enter>
if (e.keyCode !== 13 || !(buffer = components.input[0].value)) {
return;
}
// Handle command
if (buffer[0] === '/') {
parts = $.ssplit(buffer.slice(1), ' ');
command = parts[0];
payload = parts[1];
// Check that there is an handler for this command
if (!commands[command]) {
return post('error', $.template(templates.messages.unrecognized_command, { commandName: command }));
}
// Execute command handler
commands[command](payload);
2014-09-18 15:38:15 -04:00
// Clear input field
components.input[0].value = '';
2014-09-18 12:21:07 -04:00
} else /* Handle ordinary message */ {
// Make sure that the users has joined a room
if (!room) {
return post('error', templates.messages.msg_no_room);
}
// And that a valid key is set
if (!key) {
return post('error', templates.messages.msg_no_key);
}
// Before sending the message.
// Encrypt message using room UUID as salt and key as pepper.
socket.emit('message:send', {
room: room,
2014-09-18 13:17:41 -04:00
msg: $.AES.encrypt(buffer, room + key).toString(),
2014-09-18 13:48:17 -04:00
nick: (nick && nick != undefined) ? $.AES.encrypt(nick, room + key).toString() : false
2014-09-18 12:21:07 -04:00
});
// Adn the the buffer
components.input[0].value = '';
}
};
// Connect to server
socket = $.Websocket.connect(data.host);
// Bind socket events
socket
.on('connect', function () {
$(document).on('keydown', onKeyDown);
components.input.focus();
})
2014-09-18 13:17:41 -04:00
.on('room:generated', function (data) {
2014-09-18 12:21:07 -04:00
socket.emit('room:join', data);
})
.on('room:joined', function (data) {
room = data;
post('info', $.template(templates.messages.joined_room, { roomName: room }));
2014-09-19 13:25:16 -04:00
// Automatically count persons on join
socket.emit('room:count');
2014-09-18 12:21:07 -04:00
})
.on('room:left', function () {
post('info', $.template(templates.messages.left_room, { roomName: room }));
room = false;
})
.on('message:send', function (data) {
2014-09-18 13:17:41 -04:00
var decrypted = $.AES.decrypt(data.msg, room + key),
sanitized = $.escapeHtml(decrypted),
2014-09-18 13:48:17 -04:00
nick = (data.nick == undefined || !data.nick ) ? templates.default_nick : $.escapeHtml($.AES.decrypt(data.nick, room + key));
2014-09-18 12:21:07 -04:00
if (!decrypted) {
2014-09-18 13:17:41 -04:00
post('error', templates.messages.unable_to_decrypt);
2014-09-18 12:21:07 -04:00
} else {
2014-09-18 13:17:41 -04:00
post('message', sanitized, false, false, nick);
2014-09-20 09:26:43 -04:00
if( !mute ) sound.playTones(sound.messages.message);
2014-09-18 12:21:07 -04:00
}
})
.on('message:server', function (data) {
2014-09-19 13:25:16 -04:00
if( data.msg ) {
var sanitized = $.escapeHtml(data.msg);
if( templates.server[sanitized] ) {
if( data.payload !== undefined ) {
var sanitized_payload = $.escapeHtml(data.payload);
post('server', $.template(templates.server[sanitized], { payload: sanitized_payload }));
} else {
post('server', templates.server[sanitized]);
}
2014-09-20 09:26:43 -04:00
// Play sound
if (sound.messages[sanitized] !== undefined && !mute ) sound.playTones(sound.messages[sanitized]);
2014-09-19 13:25:16 -04:00
} else {
post('error', templates.server.bogus);
}
} else {
post('error', templates.server.bogus);
}
2014-09-18 12:21:07 -04:00
});
// Post the help/welcome message
2014-09-18 15:38:15 -04:00
post('motd', templates.motd, true);
2014-09-18 12:21:07 -04:00
// It's possible to provide room and key using the hashtag.
// The room and key is then seperated by semicolon (room:key).
// If there is no semicolon present, the complete hash will be treated as the room name and the key has to be set manually.
if (hash = window.location.hash) {
parts = hash.slice(1).split(':');
parts[0] && commands.join(parts[0]);
parts[1] && commands.key(parts[1]);
}
});