Initial commit
This commit is contained in:
parent
888d9ebc1f
commit
138eff9c96
|
@ -0,0 +1,80 @@
|
||||||
|
/*------------------------------------*\
|
||||||
|
GENERIC
|
||||||
|
\*------------------------------------*/
|
||||||
|
html {
|
||||||
|
-webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
|
||||||
|
-moz-box-sizing: border-box; /* Firefox, other Gecko */
|
||||||
|
box-sizing: border-box; /* Opera/IE 8+ */
|
||||||
|
}
|
||||||
|
|
||||||
|
*, *:before, *:after {
|
||||||
|
box-sizing: inherit;
|
||||||
|
|
||||||
|
font-family: monospace, 'Courier New';
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body, html {
|
||||||
|
min-height: 100%;
|
||||||
|
background-color: #000000;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0px;
|
||||||
|
margin:0px;
|
||||||
|
color: #00DD00;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------------------------*\
|
||||||
|
CHAT
|
||||||
|
\*------------------------------------*/
|
||||||
|
#chat {
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 40px;
|
||||||
|
position: absolute;
|
||||||
|
list-style-type: none;
|
||||||
|
padding:0;
|
||||||
|
margin:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Messages */
|
||||||
|
#chat li {
|
||||||
|
white-space: pre;
|
||||||
|
padding: 2px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Message types */
|
||||||
|
/* the `i` element hold the actual message */
|
||||||
|
#chat i {
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
#chat i.info { color: #7777ff; }
|
||||||
|
#chat i.server { color: #999999; }
|
||||||
|
#chat i.error { color: #ff7777; }
|
||||||
|
#chat i.message { color: #eeeeee; }
|
||||||
|
|
||||||
|
/*------------------------------------*\
|
||||||
|
INPUT
|
||||||
|
\*------------------------------------*/
|
||||||
|
#input_wrapper {
|
||||||
|
right:0;
|
||||||
|
bottom:0;
|
||||||
|
left:0;
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
height:40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#input {
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
border: 0;
|
||||||
|
outline: 0;
|
||||||
|
|
||||||
|
padding: 5px 5px 5px 15px;
|
||||||
|
|
||||||
|
color: #00dd00;
|
||||||
|
background-color:#141414;
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
<!doctype html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
|
<title>Cryptalk</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/default.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<!-- Messages -->
|
||||||
|
<!-- Each message is contained within an li element -->
|
||||||
|
<ul id="chat">
|
||||||
|
<li>SRV> Booting ...</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<!-- Message input -->
|
||||||
|
<div id="input_wrapper">
|
||||||
|
<input type="text" id="input" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Only include the script needed for loading the app -->
|
||||||
|
<script src="js/vendor/fandango.v20140918.min.js"></script>
|
||||||
|
<script src="js/bootstrap.js"></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,30 @@
|
||||||
|
// This Javascript file is the only file besides fandango.js that will be fetched through DOM.
|
||||||
|
|
||||||
|
// 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',
|
||||||
|
aes: 'https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js',
|
||||||
|
domReady: 'https://cdnjs.cloudflare.com/ajax/libs/require-domReady/2.0.1/domReady.min.js'
|
||||||
|
},
|
||||||
|
|
||||||
|
// CryptoJs AES does not support AMD modules. We'll have to create a shim.
|
||||||
|
shim: {
|
||||||
|
aes: {
|
||||||
|
exports: function () { // String (the global variable name) or a function; returning the desired variable.
|
||||||
|
return CryptoJS.AES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fetch our modules asynchronously, when the DOM is finished loading.
|
||||||
|
//define('bootstrap_module', ['domReady'], function (domReady) {
|
||||||
|
// domReady(function () {
|
||||||
|
// require(['cryptalk']);
|
||||||
|
// });
|
||||||
|
//});
|
||||||
|
|
||||||
|
// No need to wait for DOM - the Javascript is at the bottom
|
||||||
|
require(['cryptalk']);
|
|
@ -0,0 +1,129 @@
|
||||||
|
define('$', ['fandango', 'websocket', 'aes'], function (fandango, websocket, aes) {
|
||||||
|
var exports = {
|
||||||
|
selector: 0,
|
||||||
|
utilities: {},
|
||||||
|
prototype: {}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Shortcuts
|
||||||
|
utils = exports.utilities,
|
||||||
|
proto = exports.prototype,
|
||||||
|
|
||||||
|
each = fandango.each;
|
||||||
|
|
||||||
|
// The DOM selector engine
|
||||||
|
exports.selector = function (selector) {
|
||||||
|
var match,
|
||||||
|
matches = [];
|
||||||
|
|
||||||
|
if (selector === document) {
|
||||||
|
matches.push(document);
|
||||||
|
} else {
|
||||||
|
selector = selector.slice(1);
|
||||||
|
|
||||||
|
if (match = document.getElementById(selector)) {
|
||||||
|
matches.push(match);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must ALWAYS return a native array: []
|
||||||
|
return matches;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Namespace AES
|
||||||
|
utils.AES = {
|
||||||
|
decrypt: aes.decrypt,
|
||||||
|
encrypt: aes.encrypt
|
||||||
|
};
|
||||||
|
|
||||||
|
// Namespace encode
|
||||||
|
utils.AES = {
|
||||||
|
decrypt: function (string, fgh) {
|
||||||
|
return aes.decrypt(string, fgh).toString(CryptoJS.enc.Utf8);
|
||||||
|
},
|
||||||
|
encrypt: function (string, fgh) {
|
||||||
|
return aes.encrypt(string, fgh).toString();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Namespace websocket
|
||||||
|
utils.Websocket = {
|
||||||
|
connect: websocket.connect,
|
||||||
|
on: websocket.on
|
||||||
|
};
|
||||||
|
|
||||||
|
utils.ssplit = function (string, seperator) {
|
||||||
|
var components = string.split(seperator);
|
||||||
|
return [components.shift(), components.join(seperator)];
|
||||||
|
};
|
||||||
|
|
||||||
|
utils.activeElement = function () {
|
||||||
|
try { return document.activeElement; } catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A very simple implementation of sprintf()
|
||||||
|
* @param {} str [description]
|
||||||
|
* @param {[type]} map [description]
|
||||||
|
* @return {[type]} [description]
|
||||||
|
*/
|
||||||
|
utils.template = function (str, map) {
|
||||||
|
return str && str.replace(/{(\w+)}/gi, function(outer, inner) {
|
||||||
|
return map.hasOwnProperty(inner) ? map[inner] : outer /* '' */;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Originating from mustasche.js
|
||||||
|
// https://github.com/janl/mustache.js/blob/master/mustache.js#L43
|
||||||
|
utils.escapeHtml = (function () {
|
||||||
|
var pattern = /[&<>"'\/]/g,
|
||||||
|
entities = {
|
||||||
|
'&': '&',
|
||||||
|
'<': '<',
|
||||||
|
'>': '>',
|
||||||
|
'"': '"',
|
||||||
|
"'": ''',
|
||||||
|
'/': '/'
|
||||||
|
};
|
||||||
|
|
||||||
|
return function (string) {
|
||||||
|
return String(string).replace(pattern, function (s) {
|
||||||
|
return entities[s];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}());
|
||||||
|
|
||||||
|
// Extremely naive implementations of .html() and .append()
|
||||||
|
proto.html = function (string) {
|
||||||
|
each(this, function (element) {
|
||||||
|
element.innerHTML = string;
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
proto.append = function (string) {
|
||||||
|
each(this, function (element) {
|
||||||
|
element.innerHTML += string;
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Extremely naive implementations of .on()
|
||||||
|
proto.on = function (eventName, callback) {
|
||||||
|
each(this, function (element) {
|
||||||
|
element.addEventListener(eventName, callback);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
proto.focus = function () {
|
||||||
|
this[0].focus();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
return exports;
|
||||||
|
})
|
|
@ -0,0 +1,187 @@
|
||||||
|
// 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.
|
||||||
|
host: 'http://www.huset.nu:8080'
|
||||||
|
},
|
||||||
|
compiles: ['$'],
|
||||||
|
requires: ['templates']
|
||||||
|
}, function ($, requires, data) {
|
||||||
|
var socket,
|
||||||
|
key,
|
||||||
|
room,
|
||||||
|
hash,
|
||||||
|
|
||||||
|
// Collection of DOM components
|
||||||
|
components = {
|
||||||
|
chat: $('#chat'),
|
||||||
|
input: $('#input')
|
||||||
|
},
|
||||||
|
|
||||||
|
// Shortcut
|
||||||
|
templates = requires.templates,
|
||||||
|
|
||||||
|
// Adds a new message to the DOM
|
||||||
|
post = function (type, text, clearChat, clearBuffer) {
|
||||||
|
var tpl = templates.post[type],
|
||||||
|
post = $.template(tpl, text && {
|
||||||
|
text: text
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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 () {
|
||||||
|
post('info', templates.help);
|
||||||
|
},
|
||||||
|
|
||||||
|
clear: function () {
|
||||||
|
components.chat.html('');
|
||||||
|
components.input[0].value = '';
|
||||||
|
},
|
||||||
|
|
||||||
|
leave: function () {
|
||||||
|
socket.emit('room:leave', room);
|
||||||
|
},
|
||||||
|
|
||||||
|
key: function (payload) {
|
||||||
|
// Make sure the key meets the length requirements
|
||||||
|
if (payload.length < 8) {
|
||||||
|
return post('info', templates.messages.key_weak);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
},
|
||||||
|
|
||||||
|
join: function (payload) {
|
||||||
|
return (
|
||||||
|
room
|
||||||
|
? post('info', $.template(templates.messages.already_in_room, { roomName: room}))
|
||||||
|
: socket.emit('room:join', payload)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
create: function (payload) {
|
||||||
|
socket.emit('room:create');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
} 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,
|
||||||
|
msg: $.AES.encrypt(buffer, room + key)
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
})
|
||||||
|
|
||||||
|
.on('room:created', function (data) {
|
||||||
|
socket.emit('room:join', data);
|
||||||
|
})
|
||||||
|
|
||||||
|
.on('room:joined', function (data) {
|
||||||
|
room = data;
|
||||||
|
post('info', $.template(templates.messages.joined_room, { roomName: room }));
|
||||||
|
})
|
||||||
|
|
||||||
|
.on('room:left', function () {
|
||||||
|
post('info', $.template(templates.messages.left_room, { roomName: room }));
|
||||||
|
room = false;
|
||||||
|
})
|
||||||
|
|
||||||
|
.on('message:send', function (data) {
|
||||||
|
var decrypted = $.AES.decrypt(data, room + key),
|
||||||
|
sanitized = $.escapeHtml(decrypted);
|
||||||
|
|
||||||
|
if (!decrypted) {
|
||||||
|
post('info', templates.messages.unable_to_decrypt);
|
||||||
|
} else {
|
||||||
|
// Post the message, but do not clear either the chat nor the buffer.
|
||||||
|
post('message', sanitized, false, false);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
.on('message:server', function (data) {
|
||||||
|
post('server', data);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Post the help/welcome message
|
||||||
|
post('info', templates.help, true);
|
||||||
|
|
||||||
|
// 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]);
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,50 @@
|
||||||
|
// The templating function only supports variables.
|
||||||
|
// Define a variable as so: {variable_name}
|
||||||
|
define({
|
||||||
|
help: '' +
|
||||||
|
'<li> \n' +
|
||||||
|
'Cryptalk, encrypted instant chat. \n' +
|
||||||
|
' \n' +
|
||||||
|
'---------------------------------------------------------------------------------- \n' +
|
||||||
|
' \n' +
|
||||||
|
'Available commands: \n' +
|
||||||
|
' /create Creates a room \n' +
|
||||||
|
' /join RoomId Joins a room \n' +
|
||||||
|
' /leave RoomId Leaves a room \n' +
|
||||||
|
' /key OurStrongPassphrase Sets the password used for \n' +
|
||||||
|
' encryption/decryption \n' +
|
||||||
|
' /clear Clears on-screen buffer \n' +
|
||||||
|
' /help This \n' +
|
||||||
|
' \n' +
|
||||||
|
' Besides that, it\'s just to talk! \n' +
|
||||||
|
' \n' +
|
||||||
|
'Code available for review at https://www.github.com/hexagon/cryptalk \n' +
|
||||||
|
' \n' +
|
||||||
|
'--------------------------------------------------------------------------------- \n' +
|
||||||
|
'</li> ',
|
||||||
|
|
||||||
|
post: {
|
||||||
|
info: '<li>INF> <i class="info">{text}</i></li>',
|
||||||
|
server: '<li>SRV> <i class="server">{text}</i></li>',
|
||||||
|
error: '<li>ERR> <i class="error">{text}</i></li>',
|
||||||
|
message: '<li>MSG> <i class="message">{text}</i></li>'
|
||||||
|
},
|
||||||
|
|
||||||
|
messages: {
|
||||||
|
key_weak: 'Hmm, that\'s a weak key, try again...',
|
||||||
|
key_ok_ready: 'Key set, you can now start communicating.',
|
||||||
|
key_ok_but_no_room: 'Key set, you can now join a room and start communicating.',
|
||||||
|
msg_no_room: 'You have to join a room before sending messages. See /help.',
|
||||||
|
msg_no_key: 'You have to set an encryption key before sending a message. See /help.',
|
||||||
|
|
||||||
|
// Available variables: 'commandName'
|
||||||
|
unrecognized_command: 'Unrecognized command: "{commandName}"',
|
||||||
|
|
||||||
|
// Available variables: 'roomName'
|
||||||
|
joined_room: 'Joined room {roomName}',
|
||||||
|
left_room: 'Left room {roomName}',
|
||||||
|
already_in_room: 'You are already in room {roomName}, stoopid.',
|
||||||
|
|
||||||
|
unable_to_decrypt: 'Unabled to decrypt received message, keys does not match.'
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,10 @@
|
||||||
|
/*
|
||||||
|
CryptoJS v3.1.2
|
||||||
|
code.google.com/p/crypto-js
|
||||||
|
(c) 2009-2013 by Jeff Mott. All rights reserved.
|
||||||
|
code.google.com/p/crypto-js/wiki/License
|
||||||
|
*/
|
||||||
|
(function(){for(var q=CryptoJS,x=q.lib.BlockCipher,r=q.algo,j=[],y=[],z=[],A=[],B=[],C=[],s=[],u=[],v=[],w=[],g=[],k=0;256>k;k++)g[k]=128>k?k<<1:k<<1^283;for(var n=0,l=0,k=0;256>k;k++){var f=l^l<<1^l<<2^l<<3^l<<4,f=f>>>8^f&255^99;j[n]=f;y[f]=n;var t=g[n],D=g[t],E=g[D],b=257*g[f]^16843008*f;z[n]=b<<24|b>>>8;A[n]=b<<16|b>>>16;B[n]=b<<8|b>>>24;C[n]=b;b=16843009*E^65537*D^257*t^16843008*n;s[f]=b<<24|b>>>8;u[f]=b<<16|b>>>16;v[f]=b<<8|b>>>24;w[f]=b;n?(n=t^g[g[g[E^t]]],l^=g[g[l]]):n=l=1}var F=[0,1,2,4,8,
|
||||||
|
16,32,64,128,27,54],r=r.AES=x.extend({_doReset:function(){for(var c=this._key,e=c.words,a=c.sigBytes/4,c=4*((this._nRounds=a+6)+1),b=this._keySchedule=[],h=0;h<c;h++)if(h<a)b[h]=e[h];else{var d=b[h-1];h%a?6<a&&4==h%a&&(d=j[d>>>24]<<24|j[d>>>16&255]<<16|j[d>>>8&255]<<8|j[d&255]):(d=d<<8|d>>>24,d=j[d>>>24]<<24|j[d>>>16&255]<<16|j[d>>>8&255]<<8|j[d&255],d^=F[h/a|0]<<24);b[h]=b[h-a]^d}e=this._invKeySchedule=[];for(a=0;a<c;a++)h=c-a,d=a%4?b[h]:b[h-4],e[a]=4>a||4>=h?d:s[j[d>>>24]]^u[j[d>>>16&255]]^v[j[d>>>
|
||||||
|
8&255]]^w[j[d&255]]},encryptBlock:function(c,e){this._doCryptBlock(c,e,this._keySchedule,z,A,B,C,j)},decryptBlock:function(c,e){var a=c[e+1];c[e+1]=c[e+3];c[e+3]=a;this._doCryptBlock(c,e,this._invKeySchedule,s,u,v,w,y);a=c[e+1];c[e+1]=c[e+3];c[e+3]=a},_doCryptBlock:function(c,e,a,b,h,d,j,m){for(var n=this._nRounds,f=c[e]^a[0],g=c[e+1]^a[1],k=c[e+2]^a[2],p=c[e+3]^a[3],l=4,t=1;t<n;t++)var q=b[f>>>24]^h[g>>>16&255]^d[k>>>8&255]^j[p&255]^a[l++],r=b[g>>>24]^h[k>>>16&255]^d[p>>>8&255]^j[f&255]^a[l++],s=
|
||||||
|
b[k>>>24]^h[p>>>16&255]^d[f>>>8&255]^j[g&255]^a[l++],p=b[p>>>24]^h[f>>>16&255]^d[g>>>8&255]^j[k&255]^a[l++],f=q,g=r,k=s;q=(m[f>>>24]<<24|m[g>>>16&255]<<16|m[k>>>8&255]<<8|m[p&255])^a[l++];r=(m[g>>>24]<<24|m[k>>>16&255]<<16|m[p>>>8&255]<<8|m[f&255])^a[l++];s=(m[k>>>24]<<24|m[p>>>16&255]<<16|m[f>>>8&255]<<8|m[g&255])^a[l++];p=(m[p>>>24]<<24|m[f>>>16&255]<<16|m[g>>>8&255]<<8|m[k&255])^a[l++];c[e]=q;c[e+1]=r;c[e+2]=s;c[e+3]=p},keySize:8});q.AES=x._createHelper(r)})();
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Copyright (c) 2010-2011, The Dojo Foundation
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
define(function(){"use strict";function e(e){var t;for(t=0;e.length>t;t+=1)e[t](h)}function t(){var t=c;l&&t.length&&(c=[],e(t))}function i(){l||(l=!0,o&&clearInterval(o),t())}function n(e){return l?e(h):c.push(e),n}var r,s,o,a="undefined"!=typeof window&&window.document,l=!a,h=a?document:null,c=[];if(a){if(document.addEventListener)document.addEventListener("DOMContentLoaded",i,!1),window.addEventListener("load",i,!1);else if(window.attachEvent){window.attachEvent("onload",i),s=document.createElement("div");try{r=null===window.frameElement}catch(u){}s.doScroll&&r&&window.external&&(o=setInterval(function(){try{s.doScroll(),i()}catch(e){}},30))}"complete"===document.readyState&&i()}return n.version="2.0.1",n.load=function(e,t,i,r){r.isBuild?i(null):n(i)},n});
|
|
@ -0,0 +1,23 @@
|
||||||
|
(function(l){var y={"http://":1,"https://":1,"file://":1},u={deepCopy:!0,baseUrl:"",namespace:"default",timeout:1E3,paths:{}},g={};(function(){this.is=function(){var f=Object.prototype.hasOwnProperty,b=Object.prototype.toString,d={array:Array.isArray||function(a){return"[object Array]"==b.call(a)},arraylike:function(a){if(!a||!a.length&&0!==a.length||d.window(a))return!1;var c=a.length;return 1===a.nodeType||d.array(a)||!d["function"](a)&&(0===c||"number"===typeof c&&0<c&&!g.is(a,"primitive")&&c-
|
||||||
|
1 in a)},"boolean":function(a){return!0===a||!1===a},element:function(a){return!(!a||1!==a.nodeType)},finite:function(a){return isFinite(a)&&!isNaN(parseFloat(a))},integer:Number.isInteger||function(a){return"number"===typeof a&&d.finite(a)&&-9007199254740992<a&&9007199254740992>a&&Math.floor(a)===a},iterable:function(a){try{1 in obj}catch(c){return!1}return!0},nan:function(a){return d.number(a)&&a!=+a},number:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},object:function(a){return a===Object(a)},
|
||||||
|
primitive:function(a){return!0===a||!1===a||null==a||!!{string:1,number:1}[typeof a]},string:function(a){return"string"==typeof a||a instanceof String},undefined:function(a){return void 0===a},untyped:function(a){if(!a||a.nodeType||"[object Object]"!==b.call(a)||d.window(a))return!1;try{if(a.constructor&&!f.call(a,"constructor")&&!f.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}for(var e in a);return void 0===e||f.call(a,e)},window:function(a){return null!=a&&a==a.window},
|
||||||
|
empty:function(a){if(a){if(g.is(a,"array"))return 0===a.length;for(var c in a)if(f.call(a,c))return!1}return!0}},e=0,c=["Arguments","Date","Function","RegExp"];for(;4>e;e++)d[c[e].toLowerCase()]=function(a){a="[object "+a+"]";return function(c){return b.call(c)==a}}(c[e]);d.args=d.arguments;d.bool=d["boolean"];d.plain=d.untyped;return function(a,c){if(d["function"](c))return a===c(a);if(!d.string(c))return a===c;if((c=c.toLowerCase())&&d[c])return d[c](a);throw'Unknown type "'+c+'"';}}();this.each=
|
||||||
|
function(){var f=Array.prototype.some;return function(b,d,e){var c,a;if(void 0===b)return obj;e=e||g;if(f&&b.some===f)return b.some(d,e),b;if(g.is(b,"array")||g.is(b,"arraylike")){c=0;for(a=b.length;c<a&&(void 0===b[c]||!d.call(e,b[c],c,b));c++);return b}for(c in b)if(b.hasOwnProperty(c)&&d.call(e,b[c],c,b))break;return b}}();this.merge=function(f){var b,d,e,c,a;b=arguments.length;var C=!1;f=arguments[0];var w=1,z,l,A=0;if(!0===f||!1===f)C=f,f=arguments[w],w++;g.is(arguments[b-1],"function")&&(a=
|
||||||
|
arguments[b-1],b--);if(void 0===f)f={};else if(g.is(f,"primitive"))throw new TypeError("Cannot merge primitive data types: merge("+Array.prototype.join.call(arguments,", ")+")");l=g.is(f,"array");if(w<b)for(;c=arguments[w++];){l=l&&g.is(c,"array");for(e in c)d=f[e],b=c[e],void 0===b||b===f?l&&A--:(C&&b&&((z=g.is(b,"array"))||g.is(b,"untyped"))&&(b=g.merge(C,d&&(z?g.is(d,"array")?d:[]:g.is(d,"untyped")?d:{}),b,a)),a&&a(e,f,c)||(A&&(e=+e+A),f[e]=b));A=0}return f};this.subordinate=function(){function f(a){if(!a||
|
||||||
|
a.source===window&&a.data===e){var b=c.shift();a=b[0];var b=b[1],d=b.length;d?1===d?a(b[0]):2===d?a(b[0],b[1]):3===d?a(b[0],b[1],b[2]):4===d?a(b[0],b[1],b[2],b[3]):a.apply(void 0,b):a()}}var b=Array.prototype.slice,d=window.postMessage,e="__fandango@"+Math.random().toString(36),c=[],a=function(){return d?function(){d(e,"*")}:function(){setTimeout(f)}}();d&&window.addEventListener("message",f,!1);return function(e){a(c.push([arguments[arguments.length-1],b.call(arguments).slice(0,-1)])-1)}}();this.noop=
|
||||||
|
function(){};this.coalesce=function(){for(var f=0,b=arguments.length;f<b;f++)if(void 0!==arguments[f])return arguments[f]};this.hasOwn=function(f){var b=1,d=arguments.length,e,c=!0,a=!0;if(1===d)return!0;if(2===d)return f.hasOwnProperty(arguments[1]);for(;b<d;b++)if(e=arguments[b],!0===e||!1===e)a=e;else if(!f.hasOwnProperty(e)){if(a)return!1;c=!1}else if(!a)return!0;return c};this.freezeObject=Object.freeze||function(f){return object}}).call(g);var D=function(){var f={};headElement=document.getElementsByTagName("head")[0];
|
||||||
|
nativeSlice=[].slice;isOpera="undefined"!==typeof opera&&"[object Opera]"===opera.toString();createScriptNode=function(b){var d=document.createElement("script");d.setAttribute("id","script::"+b);d.type="text/javascript";d.charset="utf-8";d.async=!0;return d};useAttachEvent=!(!((useAttachEvent=createScriptNode())&&useAttachEvent.attachEvent&&useAttachEvent.attachEvent.toString&&0<useAttachEvent.attachEvent.toString().indexOf("[native code"))||isOpera);onError=function(b,d,e){return function(c){f[d]=
|
||||||
|
0;b.error=c||!0;for(e.parentElement.removeChild(e);func=b.onRejected.shift();)func(c,d)}};onProgress=function(b,d,e,c){return function(){var a,g;if(f[d]){f[d]=2;for(g=0;a=b.onProgress[g++];)a(d,e);c?e.onreadystatechange=null:(e.removeEventListener("load",b.loadListener),e.removeEventListener("error",b.errorListener));if(b.loaded.push(d)===b.load.length)for(g=0;a=b.onResolved[g++];)a(b.load)}}};isLoaded=function(b,d){for(var e=0,c;c=d[e++];)if(f[c])return!0;return!1};load=function(b){var d=0,e,c;if(0<
|
||||||
|
b.onResolved.length&&0>=b.load.length){for(;d=b.onResolved.shift();)d([]);return b.shared}for(;!b.error&&(e=b.load[d++]);)e=b.prefix+e+b.suffix,f[e]?onProgress(b,e,document.getElementById("script::"+e))():(f[e]=1,c=createScriptNode(e),useAttachEvent?c.attachEvent("onreadystatechange",onProgress(b,e,c,!0)):(b.loadListener=onProgress(b,e,c),b.errorListener=onError(b,e,c),c.addEventListener("load",b.loadListener,!1),c.addEventListener("error",b.errorListener,!1)),c.src=e,headElement.appendChild(c))};
|
||||||
|
unload=function(b){for(var d=0,e,c;e=b[d++];)(c=document.getElementById("script::"+e))&&c.parentElement.removeChild(c),f[e]=0};return function(b,d){var e,c={load:b,loaded:[],prefix:"",suffix:"",onResolved:[],onRejected:[],onProgress:[],onAlways:[],error:null,shared:e};void 0!==d&&!0!==d||load(c);e={prefix:function(a){c.prefix=a;return e},suffix:function(a){c.suffix=a;return e},now:function(){load(c);return e},and:function(a){c.load=c.load.concat(a);return e},unload:function(a){unload(a);return e},
|
||||||
|
isLoaded:function(a){return isLoaded(c,a)},done:function(){c.onResolved=c.onResolved.concat(nativeSlice.call(arguments));return e},fail:function(){c.onRejected=c.onRejected.concat(nativeSlice.call(arguments));return e},progress:function(){c.onProgress=c.onProgress.concat(nativeSlice.call(arguments));return e},always:function(){c.onAlways=c.onAlways.concat(nativeSlice.call(arguments));return e}};e["try"]=e.done;e["catch"]=e.fail;e["finally"]=e.always;e.add=e.and;return e}}(),E=function(){function f(a){var c=
|
||||||
|
function(){return[]},b={},e={},d,f;for(f=0;d=a[f++];)d.selector&&(c=d.selector),d.prototype&&("function"===typeof d.prototype?d.prototype.call(e):g.merge(e,d.prototype)),d.utilities&&("function"===typeof d.utilities?d.utilities.call(b):g.merge(b,d.utilities));var k=function(a,b,e){var d=0;a=c(a,b);this.context=b||document;this.identify=e;for(this.length=a.length;d<this.length;d++)this[d]=a[d];return this};k.prototype=e;k.prototype.length=0;k.prototype.selector="";k.prototype.splice=Array.prototype.slice;
|
||||||
|
return function(a){return g.merge(function(c,b){return new k(c,b,a)},b)}}function b(b){var e,d,h=c[b],q=g.is(h.factory,"function"),m=q?h.factory.length:0,k=h.amdStyle,r=h.compiles&&[],n=h.requires&&(k?[]:{}),l=h.inherits&&{},p,t,s;void 0===(e=h.deepCopy)&&(e=u.deepCopy);h=c[b]=g.merge(e,{},u,h);if(m&&h.requires)for(t=0;s=h.requires[t++];)k?n.push(c[s].exports):g.is(c[s].exports,"function")?n[s]=c[s].exports:g.merge(e,n[s]={},c[s].exports);if(m&&h.compiles)for(t=0;s=h.compiles[t++];)r.push(c[s].exports);
|
||||||
|
if(h.inherits)for(t=0;s=h.inherits[t++];)g.merge(e,l,c[s].exports);r&&(d=f(r));for(s in h.instances)p=h.instances[s],p.context=void 0===p.context?h.context:p.context,p.deepCopy=void 0===p.deepCopy?h.deepCopy:p.deepCopy,p.namespace=void 0===p.namespace?h.namespace:p.namespace,r=[],k?r=n:(d&&(e=function(){var a={namespace:p.namespace,module:b,instance:s};a.UID=[a.namespace,a.module,a.instance].join("/");return function(){return a}}(),d=d(e),d.identify=e,r.push(d)),n&&r.push(n),m>r.length&&r.push(p.data?
|
||||||
|
g.merge(p.deepCopy,{},p.data,h.data):h.data),m>r.length&&r.push(g.merge(p.deepCopy,{},p,h))),p.exports=q?h.factory.apply(p.context,r)||{}:h.factory,void 0===h.exports&&(h.exports=l?p.exports?g.merge(!0,{},l,p.exports):l:p.exports);h.state=3;if(a[b])for(;a[b].length;)a[b].pop()(b)}function d(d,f){var l,h=f.length,q,m,k=[],r={},n,x=[],p,t=void 0!==c[d].timeout?c[d].timeout:u.timeout,s=function(a){1===c[d].state&&(k.push(a),--h||(t&&clearTimeout(p),b(d)))};for(l=0;n=f[l++];)if(q=c[n],!q||1===q.state)(a[n]=
|
||||||
|
a[n]||[]).push(s),q||((m=u.paths[n])?g.is(m,"array")&&(m=m[0]):m=n,m=v(m),r[m]=n,x.push(m));else if(3===q.state)k.push(n);else if(2===q.state)throw Error('Could not instantiate "'+d+'"; dependency "'+n+'" has been rejected.');if(!((h=f.length)-k.length))return b(d);0<x.length&&D(x).fail(function(a,b){c[d].state=2;t&&clearTimeout(p);throw Error('Could not instantiate "'+d+'"; an error occured while trying to load "'+b+'".');}).progress(function(a){(a=r[a])&&!c[a]&&e(w,a)});t&&(p=setTimeout(function(){var a,
|
||||||
|
b,e=0,g=0;for(c[d].state=2;a=f[e++];)for(g=0;b=k[g++];)a===b&&(k.splice(--g,1),f.splice(--e,1));throw Error("Load timeout of "+t+'ms exceeded for module "'+d+'". Missing "'+f.join('", "')+'".');},t))}function e(){var a=0,f,B,h,q,m=!1,k,r,n,x;if(arguments[0]!==w){for(;(n=arguments[a++])&&(_type=(typeof n)[0]);)if("s"===_type?k?x=1:k=n:"f"===_type?q?r?x=1:r=n:q=n:"o"===_type&&(g.is(n,"array")?(f={requires:n},m=!0):f?q=n:f=n),x)throw new TypeError("define called with unrecognized signature; `"+Array.prototype.join.call(arguments,
|
||||||
|
", ")+"`.");f=f||{};k=k||f.UID;q=q||f.factory;r=r||f.onRejected}else{if(!(a=l.pop()))throw Error("Inconsistent naming queue");k=arguments[1];f=a[0];q=a[1];r=a[3]}if(!q)if(f)q=f,f={};else throw Error('Missing factory for module "'+k+'"');if(c[k])throw Error('Duplicate entry for module "'+k+'"');if(k)if(a=c[k]=f,a.UID=k,a.amdStyle=m,a.factory=q,a.state=1,a.requires=g.is(a.requires,"array")&&a.requires,a.inherits=g.is(a.inherits,"array")&&a.inherits,a.compiles=g.is(a.compiles,"array")&&a.compiles,a.instances||
|
||||||
|
(a.instances={instance1:{}}),a.requires||a.compiles||a.inherits){m=[a.requires,a.inherits,a.compiles];m=[];a.requires&&z.apply(m,a.requires);a.inherits&&z.apply(m,a.inherits);a.compiles&&z.apply(m,a.compiles);for(a=0;f=m[a++];)if(c[f]&&3===c[f].state)m.splice(--a,1);else if(B=u.shim[f])h=v(u.paths[f]||h),q=g.is(B.exports,"function")?B.exports:function(){return window[B.exports]},D([h]).done(function(a,b){return function(){e(a,b)}}(f,q));m.length?g.subordinate(k,m,d):b(k)}else b(k);else l.unshift([f,
|
||||||
|
q,r])}var c={},a={},l=[],w={sentinel:1},z=Array.prototype.push,v=function(a){var b=a.toLowerCase(),c=b[0];"/"===c||"\\"===c||"h"===c&&(y[b.slice(0,7)]||y[b.slice(0,8)])||"f"===c&&y[b.slice(0,7)]||(a=u.baseUrl+a);".js"!==a.slice(-3)&&(a+=".js");return a};e.amd={};return e}();E("fandango",function(){return g});var F=l.fandango,G=l.define,v={fn:g,define:E,require:function(f){var b,d,e,c,a=[];for(b=0;d=f[b++];)e=d.toLowerCase(),c=e.slice(0,1),(isAbsolutePath=!!("/"===c||"\\"===c||"h"===c&&(y[e.slice(0,
|
||||||
|
7)]||y[e.slice(0,8)])||"f"===c&&y[e.slice(0,7)]))||(d=u.baseUrl+d),e.slice(-3)&&(d+=".js"),a.push(d);return D(a)},noConflict:function(f){l.define===E&&(l.define=G);f&&l.fandango===v&&(l.fandango=F);return v},defaults:function(f){return f?g.merge(u,f):u}};l.define||(l.define=v.define);l.require||(l.require=v.require);l.fandango=v})(this);
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,39 @@
|
||||||
|
var express = require('express.io'),
|
||||||
|
uuid = require('node-uuid');
|
||||||
|
|
||||||
|
app = express();app.http().io();
|
||||||
|
|
||||||
|
app.use(express.static(__dirname + '/public'));
|
||||||
|
|
||||||
|
app.io.route('room', {
|
||||||
|
create: function(req) {
|
||||||
|
var room = uuid.v4();
|
||||||
|
req.socket.emit('message:server', 'Room ' + room + ' created');
|
||||||
|
req.socket.emit('room:created',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', 'A person joined this room');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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', 'A person left this room');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.io.route('message', {
|
||||||
|
send: function(req) {
|
||||||
|
if(req.data && req.data.room) req.socket.broadcast.to(req.data.room).emit('message:send', req.data.msg);
|
||||||
|
req.socket.emit('message:send', req.data.msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(8080, function(){
|
||||||
|
console.log('listening on *:8080');
|
||||||
|
});
|
Loading…
Reference in New Issue