Initial commit

This commit is contained in:
Hexagon 2014-09-18 18:21:07 +02:00
parent 888d9ebc1f
commit 138eff9c96
11 changed files with 603 additions and 0 deletions

80
public/css/default.css Normal file
View File

@ -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;
}

27
public/index.html Normal file
View File

@ -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>

30
public/js/bootstrap.js vendored Normal file
View File

@ -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']);

View File

@ -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 = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;',
'/': '&#x2F;'
};
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;
})

View File

@ -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]);
}
});

View File

@ -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.'
}
});

10
public/js/vendor/aes.v3.1.2.min.js vendored Normal file
View File

@ -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)})();

26
public/js/vendor/domReady.v2.0.1.min.js vendored Normal file
View File

@ -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});

View File

@ -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);

2
public/js/vendor/socket.io.v0.9.16.min.js generated vendored Normal file

File diff suppressed because one or more lines are too long

39
server.js Normal file
View File

@ -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');
});