Seperated common crypto operations to common file and made common toolbar used for both pad and spreadsheet
This commit is contained in:
parent
e039e90a24
commit
0e44b10aeb
77
www/common/crypto.js
Normal file
77
www/common/crypto.js
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
define([
|
||||||
|
'/bower_components/tweetnacl/nacl-fast.min.js',
|
||||||
|
], function () {
|
||||||
|
var Nacl = window.nacl;
|
||||||
|
var module = { exports: {} };
|
||||||
|
|
||||||
|
var encryptStr = function (str, key) {
|
||||||
|
var array = Nacl.util.decodeUTF8(str);
|
||||||
|
var nonce = Nacl.randomBytes(24);
|
||||||
|
var packed = Nacl.secretbox(array, nonce, key);
|
||||||
|
if (!packed) { throw new Error(); }
|
||||||
|
return Nacl.util.encodeBase64(nonce) + "|" + Nacl.util.encodeBase64(packed);
|
||||||
|
};
|
||||||
|
|
||||||
|
var decryptStr = function (str, key) {
|
||||||
|
var arr = str.split('|');
|
||||||
|
if (arr.length !== 2) { throw new Error(); }
|
||||||
|
var nonce = Nacl.util.decodeBase64(arr[0]);
|
||||||
|
var packed = Nacl.util.decodeBase64(arr[1]);
|
||||||
|
var unpacked = Nacl.secretbox.open(packed, nonce, key);
|
||||||
|
if (!unpacked) { throw new Error(); }
|
||||||
|
return Nacl.util.encodeUTF8(unpacked);
|
||||||
|
};
|
||||||
|
|
||||||
|
// this is crap because of bencoding messages... it should go away....
|
||||||
|
var splitMessage = function (msg, sending) {
|
||||||
|
var idx = 0;
|
||||||
|
var nl;
|
||||||
|
for (var i = ((sending) ? 0 : 1); i < 3; i++) {
|
||||||
|
nl = msg.indexOf(':',idx);
|
||||||
|
idx = nl + Number(msg.substring(idx,nl)) + 1;
|
||||||
|
}
|
||||||
|
return [ msg.substring(0,idx), msg.substring(msg.indexOf(':',idx) + 1) ];
|
||||||
|
};
|
||||||
|
|
||||||
|
var encrypt = module.exports.encrypt = function (msg, key) {
|
||||||
|
var spl = splitMessage(msg, true);
|
||||||
|
var json = JSON.parse(spl[1]);
|
||||||
|
// non-patches are not encrypted.
|
||||||
|
if (json[0] !== 2) { return msg; }
|
||||||
|
json[1] = encryptStr(JSON.stringify(json[1]), key);
|
||||||
|
var res = JSON.stringify(json);
|
||||||
|
return spl[0] + res.length + ':' + res;
|
||||||
|
};
|
||||||
|
|
||||||
|
var decrypt = module.exports.decrypt = function (msg, key) {
|
||||||
|
var spl = splitMessage(msg, false);
|
||||||
|
var json = JSON.parse(spl[1]);
|
||||||
|
// non-patches are not encrypted.
|
||||||
|
if (json[0] !== 2) { return msg; }
|
||||||
|
if (typeof(json[1]) !== 'string') { throw new Error(); }
|
||||||
|
json[1] = JSON.parse(decryptStr(json[1], key));
|
||||||
|
var res = JSON.stringify(json);
|
||||||
|
return spl[0] + res.length + ':' + res;
|
||||||
|
};
|
||||||
|
|
||||||
|
var parseKey = module.exports.parseKey = function (str) {
|
||||||
|
var array = Nacl.util.decodeBase64(str);
|
||||||
|
var hash = Nacl.hash(array);
|
||||||
|
var lk = hash.subarray(32);
|
||||||
|
return {
|
||||||
|
lookupKey: lk,
|
||||||
|
cryptKey: hash.subarray(0,32),
|
||||||
|
channel: Nacl.util.encodeBase64(lk).substring(0,10)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var rand64 = module.exports.rand64 = function (bytes) {
|
||||||
|
return Nacl.util.encodeBase64(Nacl.randomBytes(bytes));
|
||||||
|
};
|
||||||
|
|
||||||
|
var genKey = module.exports.genKey = function () {
|
||||||
|
return rand64(18);
|
||||||
|
};
|
||||||
|
|
||||||
|
return module.exports;
|
||||||
|
});
|
||||||
@ -1,4 +1,6 @@
|
|||||||
var Toolbar = function ($, container, Messages, myUserName, realtime) {
|
define([
|
||||||
|
'/common/messages.js'
|
||||||
|
], function (Messages) {
|
||||||
|
|
||||||
/** Id of the element for getting debug info. */
|
/** Id of the element for getting debug info. */
|
||||||
var DEBUG_LINK_CLS = 'rtwysiwyg-debug-link';
|
var DEBUG_LINK_CLS = 'rtwysiwyg-debug-link';
|
||||||
@ -22,15 +24,15 @@ var Toolbar = function ($, container, Messages, myUserName, realtime) {
|
|||||||
return 'rtwysiwyg-uid-' + String(Math.random()).substring(2);
|
return 'rtwysiwyg-uid-' + String(Math.random()).substring(2);
|
||||||
};
|
};
|
||||||
|
|
||||||
var createRealtimeToolbar = function (container) {
|
var createRealtimeToolbar = function ($container) {
|
||||||
var id = uid();
|
var id = uid();
|
||||||
$(container).prepend(
|
$container.prepend(
|
||||||
'<div class="' + TOOLBAR_CLS + '" id="' + id + '">' +
|
'<div class="' + TOOLBAR_CLS + '" id="' + id + '">' +
|
||||||
'<div class="rtwysiwyg-toolbar-leftside"></div>' +
|
'<div class="rtwysiwyg-toolbar-leftside"></div>' +
|
||||||
'<div class="rtwysiwyg-toolbar-rightside"></div>' +
|
'<div class="rtwysiwyg-toolbar-rightside"></div>' +
|
||||||
'</div>'
|
'</div>'
|
||||||
);
|
);
|
||||||
var toolbar = $('#'+id);
|
var toolbar = $container.find('#'+id);
|
||||||
toolbar.append([
|
toolbar.append([
|
||||||
'<style>',
|
'<style>',
|
||||||
'.' + TOOLBAR_CLS + ' {',
|
'.' + TOOLBAR_CLS + ' {',
|
||||||
@ -77,10 +79,10 @@ var Toolbar = function ($, container, Messages, myUserName, realtime) {
|
|||||||
return toolbar;
|
return toolbar;
|
||||||
};
|
};
|
||||||
|
|
||||||
var createSpinner = function (container) {
|
var createSpinner = function ($container) {
|
||||||
var id = uid();
|
var id = uid();
|
||||||
$(container).append('<div class="rtwysiwyg-spinner" id="'+id+'"></div>');
|
$container.append('<div class="rtwysiwyg-spinner" id="'+id+'"></div>');
|
||||||
return $('#'+id)[0];
|
return $container.find('#'+id)[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
var kickSpinner = function (spinnerElement, reversed) {
|
var kickSpinner = function (spinnerElement, reversed) {
|
||||||
@ -93,10 +95,10 @@ var Toolbar = function ($, container, Messages, myUserName, realtime) {
|
|||||||
}, SPINNER_DISAPPEAR_TIME);
|
}, SPINNER_DISAPPEAR_TIME);
|
||||||
};
|
};
|
||||||
|
|
||||||
var createUserList = function (container) {
|
var createUserList = function ($container) {
|
||||||
var id = uid();
|
var id = uid();
|
||||||
$(container).prepend('<div class="' + USER_LIST_CLS + '" id="'+id+'"></div>');
|
$container.prepend('<div class="' + USER_LIST_CLS + '" id="'+id+'"></div>');
|
||||||
return $('#'+id)[0];
|
return $container.find('#'+id)[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
var updateUserList = function (myUserName, listElement, userList) {
|
var updateUserList = function (myUserName, listElement, userList) {
|
||||||
@ -115,10 +117,10 @@ var Toolbar = function ($, container, Messages, myUserName, realtime) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var createLagElement = function (container) {
|
var createLagElement = function ($container) {
|
||||||
var id = uid();
|
var id = uid();
|
||||||
$(container).append('<div class="' + LAG_ELEM_CLS + '" id="'+id+'"></div>');
|
$container.append('<div class="' + LAG_ELEM_CLS + '" id="'+id+'"></div>');
|
||||||
return $('#'+id)[0];
|
return $container.find('#'+id)[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
var checkLag = function (realtime, lagElement) {
|
var checkLag = function (realtime, lagElement) {
|
||||||
@ -133,40 +135,49 @@ var Toolbar = function ($, container, Messages, myUserName, realtime) {
|
|||||||
lagElement.textContent = lagMsg;
|
lagElement.textContent = lagMsg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var create = function ($container, myUserName, realtime) {
|
||||||
|
var toolbar = createRealtimeToolbar($container);
|
||||||
|
var userListElement = createUserList(toolbar.find('.rtwysiwyg-toolbar-leftside'));
|
||||||
|
var spinner = createSpinner(toolbar.find('.rtwysiwyg-toolbar-rightside'));
|
||||||
|
var lagElement = createLagElement(toolbar.find('.rtwysiwyg-toolbar-rightside'));
|
||||||
|
|
||||||
var toolbar = createRealtimeToolbar(container);
|
var connected = false;
|
||||||
var userListElement = createUserList(toolbar.find('.rtwysiwyg-toolbar-leftside'));
|
|
||||||
var spinner = createSpinner(toolbar.find('.rtwysiwyg-toolbar-rightside'));
|
|
||||||
var lagElement = createLagElement(toolbar.find('.rtwysiwyg-toolbar-rightside'));
|
|
||||||
|
|
||||||
var connected = false;
|
realtime.onUserListChange(function (userList) {
|
||||||
|
if (userList.indexOf(myUserName) !== -1) { connected = true; }
|
||||||
|
if (!connected) { return; }
|
||||||
|
updateUserList(myUserName, userListElement, userList);
|
||||||
|
});
|
||||||
|
|
||||||
realtime.onUserListChange(function (userList) {
|
var ks = function () {
|
||||||
if (userList.indexOf(myUserName) !== -1) { connected = true; }
|
if (connected) { kickSpinner(spinner, false); }
|
||||||
if (!connected) { return; }
|
};
|
||||||
updateUserList(myUserName, userListElement, userList);
|
|
||||||
});
|
|
||||||
|
|
||||||
var ks = function () {
|
realtime.onPatch(ks);
|
||||||
if (connected) { kickSpinner(spinner, false); }
|
// Try to filter out non-patch messages, doesn't have to be perfect this is just the spinner
|
||||||
|
realtime.onMessage(function (msg) { if (msg.indexOf(':[2,') > -1) { ks(); } });
|
||||||
|
|
||||||
|
setInterval(function () {
|
||||||
|
if (!connected) { return; }
|
||||||
|
checkLag(realtime, lagElement);
|
||||||
|
}, 3000);
|
||||||
|
|
||||||
|
return {
|
||||||
|
failed: function () {
|
||||||
|
connected = false;
|
||||||
|
userListElement.textContent = '';
|
||||||
|
lagElement.textContent = '';
|
||||||
|
},
|
||||||
|
reconnecting: function () {
|
||||||
|
connected = false;
|
||||||
|
userListElement.textContent = Messages.reconnecting;
|
||||||
|
lagElement.textContent = '';
|
||||||
|
},
|
||||||
|
connected: function () {
|
||||||
|
connected = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
realtime.onPatch(ks);
|
return { create: create };
|
||||||
realtime.onMessage(ks);
|
});
|
||||||
|
|
||||||
setInterval(function () {
|
|
||||||
if (!connected) { return; }
|
|
||||||
checkLag(realtime, lagElement);
|
|
||||||
}, 3000);
|
|
||||||
|
|
||||||
return {
|
|
||||||
reconnecting: function () {
|
|
||||||
connected = false;
|
|
||||||
userListElement.textContent = Messages.reconnecting;
|
|
||||||
lagElement.textContent = '';
|
|
||||||
},
|
|
||||||
connected: function () {
|
|
||||||
connected = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|||||||
@ -2,39 +2,22 @@ define([
|
|||||||
'/api/config?cb=' + Math.random().toString(16).substring(2),
|
'/api/config?cb=' + Math.random().toString(16).substring(2),
|
||||||
'/pad/realtime-wysiwyg.js',
|
'/pad/realtime-wysiwyg.js',
|
||||||
'/common/messages.js',
|
'/common/messages.js',
|
||||||
|
'/common/crypto.js',
|
||||||
'/bower_components/jquery/dist/jquery.min.js',
|
'/bower_components/jquery/dist/jquery.min.js',
|
||||||
'/bower_components/ckeditor/ckeditor.js',
|
'/bower_components/ckeditor/ckeditor.js',
|
||||||
'/bower_components/tweetnacl/nacl-fast.min.js',
|
], function (Config, RTWysiwyg, Messages, Crypto) {
|
||||||
], function (Config, RTWysiwyg, Messages) {
|
|
||||||
var Ckeditor = window.CKEDITOR;
|
var Ckeditor = window.CKEDITOR;
|
||||||
var Nacl = window.nacl;
|
var $ = window.jQuery;
|
||||||
var $ = jQuery;
|
|
||||||
|
|
||||||
var module = { exports: {} };
|
|
||||||
|
|
||||||
var parseKey = function (str) {
|
|
||||||
var array = Nacl.util.decodeBase64(str);
|
|
||||||
var hash = Nacl.hash(array);
|
|
||||||
return { lookupKey: hash.subarray(32), cryptKey: hash.subarray(0,32) };
|
|
||||||
};
|
|
||||||
|
|
||||||
var genKey = function () {
|
|
||||||
return Nacl.util.encodeBase64(Nacl.randomBytes(18));
|
|
||||||
};
|
|
||||||
|
|
||||||
var userName = function () {
|
|
||||||
return Nacl.util.encodeBase64(Nacl.randomBytes(8));
|
|
||||||
};
|
|
||||||
|
|
||||||
$(function () {
|
$(function () {
|
||||||
$(window).on('hashchange', function() {
|
$(window).on('hashchange', function() {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
});
|
});
|
||||||
if (window.location.href.indexOf('#') === -1) {
|
if (window.location.href.indexOf('#') === -1) {
|
||||||
window.location.href = window.location.href + '#' + genKey();
|
window.location.href = window.location.href + '#' + Crypto.genKey();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var key = parseKey(window.location.hash.substring(1));
|
var key = Crypto.parseKey(window.location.hash.substring(1));
|
||||||
var editor = Ckeditor.replace('editor1', {
|
var editor = Ckeditor.replace('editor1', {
|
||||||
removeButtons: 'Source,Maximize',
|
removeButtons: 'Source,Maximize',
|
||||||
// This plugin inserts html crap into the document which is not part of the document
|
// This plugin inserts html crap into the document which is not part of the document
|
||||||
@ -48,8 +31,8 @@ define([
|
|||||||
|
|
||||||
var rtw =
|
var rtw =
|
||||||
RTWysiwyg.start(Config.websocketURL,
|
RTWysiwyg.start(Config.websocketURL,
|
||||||
userName(),
|
Crypto.rand64(8),
|
||||||
Nacl.util.encodeBase64(key.lookupKey).substring(0,10),
|
key.channel,
|
||||||
key.cryptKey);
|
key.cryptKey);
|
||||||
editor.on('change', function () { rtw.onEvent(); });
|
editor.on('change', function () { rtw.onEvent(); });
|
||||||
});
|
});
|
||||||
|
|||||||
@ -19,13 +19,13 @@ define([
|
|||||||
'/pad/errorbox.js',
|
'/pad/errorbox.js',
|
||||||
'/common/messages.js',
|
'/common/messages.js',
|
||||||
'/bower_components/reconnectingWebsocket/reconnecting-websocket.js',
|
'/bower_components/reconnectingWebsocket/reconnecting-websocket.js',
|
||||||
|
'/common/crypto.js',
|
||||||
|
'/common/toolbar.js',
|
||||||
'/pad/rangy.js',
|
'/pad/rangy.js',
|
||||||
'/common/chainpad.js',
|
'/common/chainpad.js',
|
||||||
'/common/otaml.js',
|
'/common/otaml.js',
|
||||||
'/common/toolbar.js',
|
|
||||||
'/bower_components/jquery/dist/jquery.min.js',
|
'/bower_components/jquery/dist/jquery.min.js',
|
||||||
'/bower_components/tweetnacl/nacl-fast.min.js'
|
], function (HTMLPatcher, ErrorBox, Messages, ReconnectingWebSocket, Crypto, Toolbar) {
|
||||||
], function (HTMLPatcher, ErrorBox, Messages, ReconnectingWebSocket) {
|
|
||||||
|
|
||||||
window.ErrorBox = ErrorBox;
|
window.ErrorBox = ErrorBox;
|
||||||
|
|
||||||
@ -34,7 +34,6 @@ window.ErrorBox = ErrorBox;
|
|||||||
Rangy.init();
|
Rangy.init();
|
||||||
var ChainPad = window.ChainPad;
|
var ChainPad = window.ChainPad;
|
||||||
var Otaml = window.Otaml;
|
var Otaml = window.Otaml;
|
||||||
var Nacl = window.nacl;
|
|
||||||
|
|
||||||
var PARANOIA = true;
|
var PARANOIA = true;
|
||||||
|
|
||||||
@ -49,23 +48,6 @@ window.ErrorBox = ErrorBox;
|
|||||||
/** Maximum number of milliseconds of lag before we fail the connection. */
|
/** Maximum number of milliseconds of lag before we fail the connection. */
|
||||||
var MAX_LAG_BEFORE_DISCONNECT = 20000;
|
var MAX_LAG_BEFORE_DISCONNECT = 20000;
|
||||||
|
|
||||||
/** Id of the element for getting debug info. */
|
|
||||||
var DEBUG_LINK_CLS = 'rtwysiwyg-debug-link';
|
|
||||||
|
|
||||||
/** Id of the div containing the user list. */
|
|
||||||
var USER_LIST_CLS = 'rtwysiwyg-user-list';
|
|
||||||
|
|
||||||
/** Id of the div containing the lag info. */
|
|
||||||
var LAG_ELEM_CLS = 'rtwysiwyg-lag';
|
|
||||||
|
|
||||||
/** The toolbar class which contains the user list, debug link and lag. */
|
|
||||||
var TOOLBAR_CLS = 'rtwysiwyg-toolbar';
|
|
||||||
|
|
||||||
/** Key in the localStore which indicates realtime activity should be disallowed. */
|
|
||||||
var LOCALSTORAGE_DISALLOW = 'rtwysiwyg-disallow';
|
|
||||||
|
|
||||||
var SPINNER_DISAPPEAR_TIME = 3000;
|
|
||||||
|
|
||||||
// ------------------ Trapping Keyboard Events ---------------------- //
|
// ------------------ Trapping Keyboard Events ---------------------- //
|
||||||
|
|
||||||
var bindEvents = function (element, events, callback, unbind) {
|
var bindEvents = function (element, events, callback, unbind) {
|
||||||
@ -108,9 +90,8 @@ window.ErrorBox = ErrorBox;
|
|||||||
|
|
||||||
var abort = function (socket, realtime) {
|
var abort = function (socket, realtime) {
|
||||||
realtime.abort();
|
realtime.abort();
|
||||||
|
realtime.toolbar.failed();
|
||||||
try { socket._socket.close(); } catch (e) { }
|
try { socket._socket.close(); } catch (e) { }
|
||||||
$('.'+USER_LIST_CLS).text(Messages.disconnected);
|
|
||||||
$('.'+LAG_ELEM_CLS).text("");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var createDebugInfo = function (cause, realtime, docHTML, allMessages) {
|
var createDebugInfo = function (cause, realtime, docHTML, allMessages) {
|
||||||
@ -266,55 +247,6 @@ window.ErrorBox = ErrorBox;
|
|||||||
return out;
|
return out;
|
||||||
};
|
};
|
||||||
|
|
||||||
var encryptStr = function (str, key) {
|
|
||||||
var array = Nacl.util.decodeUTF8(str);
|
|
||||||
var nonce = Nacl.randomBytes(24);
|
|
||||||
var packed = Nacl.secretbox(array, nonce, key);
|
|
||||||
if (!packed) { throw new Error(); }
|
|
||||||
return Nacl.util.encodeBase64(nonce) + "|" + Nacl.util.encodeBase64(packed);
|
|
||||||
};
|
|
||||||
var decryptStr = function (str, key) {
|
|
||||||
var arr = str.split('|');
|
|
||||||
if (arr.length !== 2) { throw new Error(); }
|
|
||||||
var nonce = Nacl.util.decodeBase64(arr[0]);
|
|
||||||
var packed = Nacl.util.decodeBase64(arr[1]);
|
|
||||||
var unpacked = Nacl.secretbox.open(packed, nonce, key);
|
|
||||||
if (!unpacked) { throw new Error(); }
|
|
||||||
return Nacl.util.encodeUTF8(unpacked);
|
|
||||||
};
|
|
||||||
|
|
||||||
// this is crap because of bencoding messages... it should go away....
|
|
||||||
var splitMessage = function (msg, sending) {
|
|
||||||
var idx = 0;
|
|
||||||
var nl;
|
|
||||||
for (var i = ((sending) ? 0 : 1); i < 3; i++) {
|
|
||||||
nl = msg.indexOf(':',idx);
|
|
||||||
idx = nl + Number(msg.substring(idx,nl)) + 1;
|
|
||||||
}
|
|
||||||
return [ msg.substring(0,idx), msg.substring(msg.indexOf(':',idx) + 1) ];
|
|
||||||
};
|
|
||||||
|
|
||||||
var encrypt = function (msg, key) {
|
|
||||||
var spl = splitMessage(msg, true);
|
|
||||||
var json = JSON.parse(spl[1]);
|
|
||||||
// non-patches are not encrypted.
|
|
||||||
if (json[0] !== 2) { return msg; }
|
|
||||||
json[1] = encryptStr(JSON.stringify(json[1]), key);
|
|
||||||
var res = JSON.stringify(json);
|
|
||||||
return spl[0] + res.length + ':' + res;
|
|
||||||
};
|
|
||||||
|
|
||||||
var decrypt = function (msg, key) {
|
|
||||||
var spl = splitMessage(msg, false);
|
|
||||||
var json = JSON.parse(spl[1]);
|
|
||||||
// non-patches are not encrypted.
|
|
||||||
if (json[0] !== 2) { return msg; }
|
|
||||||
if (typeof(json[1]) !== 'string') { throw new Error(); }
|
|
||||||
json[1] = JSON.parse(decryptStr(json[1], key));
|
|
||||||
var res = JSON.stringify(json);
|
|
||||||
return spl[0] + res.length + ':' + res;
|
|
||||||
};
|
|
||||||
|
|
||||||
var start = module.exports.start = function (websocketUrl, userName, channel, cryptKey)
|
var start = module.exports.start = function (websocketUrl, userName, channel, cryptKey)
|
||||||
{
|
{
|
||||||
var passwd = 'y';
|
var passwd = 'y';
|
||||||
@ -370,7 +302,8 @@ console.log(new Error().stack);
|
|||||||
getDocHTML(doc),
|
getDocHTML(doc),
|
||||||
{ transformFunction: Otaml.transform });
|
{ transformFunction: Otaml.transform });
|
||||||
|
|
||||||
var toolbar = Toolbar($, $('#cke_1_toolbox'), Messages, userName, realtime);
|
var toolbar = realtime.toolbar =
|
||||||
|
Toolbar.create($('#cke_1_toolbox'), userName, realtime);
|
||||||
|
|
||||||
onEvent = function () {
|
onEvent = function () {
|
||||||
if (isErrorState) { return; }
|
if (isErrorState) { return; }
|
||||||
@ -417,7 +350,7 @@ console.log(new Error().stack);
|
|||||||
|
|
||||||
socket.onMessage.push(function (evt) {
|
socket.onMessage.push(function (evt) {
|
||||||
if (isErrorState) { return; }
|
if (isErrorState) { return; }
|
||||||
var message = decrypt(evt.data, cryptKey);
|
var message = Crypto.decrypt(evt.data, cryptKey);
|
||||||
allMessages.push(message);
|
allMessages.push(message);
|
||||||
if (!initializing) {
|
if (!initializing) {
|
||||||
if (PARANOIA) { onEvent(); }
|
if (PARANOIA) { onEvent(); }
|
||||||
@ -427,7 +360,7 @@ console.log(new Error().stack);
|
|||||||
});
|
});
|
||||||
realtime.onMessage(function (message) {
|
realtime.onMessage(function (message) {
|
||||||
if (isErrorState) { return; }
|
if (isErrorState) { return; }
|
||||||
message = encrypt(message, cryptKey);
|
message = Crypto.encrypt(message, cryptKey);
|
||||||
try {
|
try {
|
||||||
socket.send(message);
|
socket.send(message);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@ -1,34 +1,18 @@
|
|||||||
define([
|
define([
|
||||||
'/api/config?cb=' + Math.random().toString(16).substring(2),
|
'/api/config?cb=' + Math.random().toString(16).substring(2),
|
||||||
'/common/messages.js',
|
'/common/messages.js',
|
||||||
|
'/common/crypto.js',
|
||||||
'/common/toolbar.js',
|
'/common/toolbar.js',
|
||||||
'/common/chainpad.js',
|
'/common/chainpad.js',
|
||||||
'/bower_components/jquery/dist/jquery.min.js',
|
'/bower_components/jquery/dist/jquery.min.js',
|
||||||
'/bower_components/tweetnacl/nacl-fast.min.js',
|
|
||||||
'/common/otaml.js'
|
'/common/otaml.js'
|
||||||
], function (Config, Messages) {
|
], function (Config, Messages, Crypto, Toolbar) {
|
||||||
var Nacl = window.nacl;
|
|
||||||
var $ = jQuery;
|
var $ = jQuery;
|
||||||
var ChainPad = window.ChainPad;
|
var ChainPad = window.ChainPad;
|
||||||
var Otaml = window.Otaml;
|
var Otaml = window.Otaml;
|
||||||
var Toolbar = window.Toolbar;
|
|
||||||
|
|
||||||
var module = { exports: {} };
|
var module = { exports: {} };
|
||||||
|
|
||||||
var parseKey = function (str) {
|
|
||||||
var array = Nacl.util.decodeBase64(str);
|
|
||||||
var hash = Nacl.hash(array);
|
|
||||||
return { lookupKey: hash.subarray(32), cryptKey: hash.subarray(0,32) };
|
|
||||||
};
|
|
||||||
|
|
||||||
var genKey = function () {
|
|
||||||
return Nacl.util.encodeBase64(Nacl.randomBytes(18));
|
|
||||||
};
|
|
||||||
|
|
||||||
var userName = function () {
|
|
||||||
return 'Other-' + Nacl.util.encodeBase64(Nacl.randomBytes(8));
|
|
||||||
};
|
|
||||||
|
|
||||||
var sheetToJson = function (ifrWindow) {
|
var sheetToJson = function (ifrWindow) {
|
||||||
var xx = ifrWindow.sh[0].jS
|
var xx = ifrWindow.sh[0].jS
|
||||||
var m = [];
|
var m = [];
|
||||||
@ -65,55 +49,6 @@ define([
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var encryptStr = function (str, key) {
|
|
||||||
var array = Nacl.util.decodeUTF8(str);
|
|
||||||
var nonce = Nacl.randomBytes(24);
|
|
||||||
var packed = Nacl.secretbox(array, nonce, key);
|
|
||||||
if (!packed) { throw new Error(); }
|
|
||||||
return Nacl.util.encodeBase64(nonce) + "|" + Nacl.util.encodeBase64(packed);
|
|
||||||
};
|
|
||||||
var decryptStr = function (str, key) {
|
|
||||||
var arr = str.split('|');
|
|
||||||
if (arr.length !== 2) { throw new Error(); }
|
|
||||||
var nonce = Nacl.util.decodeBase64(arr[0]);
|
|
||||||
var packed = Nacl.util.decodeBase64(arr[1]);
|
|
||||||
var unpacked = Nacl.secretbox.open(packed, nonce, key);
|
|
||||||
if (!unpacked) { throw new Error(); }
|
|
||||||
return Nacl.util.encodeUTF8(unpacked);
|
|
||||||
};
|
|
||||||
|
|
||||||
// this is crap because of bencoding messages... it should go away....
|
|
||||||
var splitMessage = function (msg, sending) {
|
|
||||||
var idx = 0;
|
|
||||||
var nl;
|
|
||||||
for (var i = ((sending) ? 0 : 1); i < 3; i++) {
|
|
||||||
nl = msg.indexOf(':',idx);
|
|
||||||
idx = nl + Number(msg.substring(idx,nl)) + 1;
|
|
||||||
}
|
|
||||||
return [ msg.substring(0,idx), msg.substring(msg.indexOf(':',idx) + 1) ];
|
|
||||||
};
|
|
||||||
|
|
||||||
var encrypt = function (msg, key) {
|
|
||||||
var spl = splitMessage(msg, true);
|
|
||||||
var json = JSON.parse(spl[1]);
|
|
||||||
// non-patches are not encrypted.
|
|
||||||
if (json[0] !== 2) { return msg; }
|
|
||||||
json[1] = encryptStr(JSON.stringify(json[1]), key);
|
|
||||||
var res = JSON.stringify(json);
|
|
||||||
return spl[0] + res.length + ':' + res;
|
|
||||||
};
|
|
||||||
|
|
||||||
var decrypt = function (msg, key) {
|
|
||||||
var spl = splitMessage(msg, false);
|
|
||||||
var json = JSON.parse(spl[1]);
|
|
||||||
// non-patches are not encrypted.
|
|
||||||
if (json[0] !== 2) { return msg; }
|
|
||||||
if (typeof(json[1]) !== 'string') { throw new Error(); }
|
|
||||||
json[1] = JSON.parse(decryptStr(json[1], key));
|
|
||||||
var res = JSON.stringify(json);
|
|
||||||
return spl[0] + res.length + ':' + res;
|
|
||||||
};
|
|
||||||
|
|
||||||
var applyChange = function(ctx, oldval, newval) {
|
var applyChange = function(ctx, oldval, newval) {
|
||||||
if (oldval === newval) return;
|
if (oldval === newval) return;
|
||||||
|
|
||||||
@ -139,7 +74,7 @@ define([
|
|||||||
$(function () {
|
$(function () {
|
||||||
|
|
||||||
if (window.location.href.indexOf('#') === -1) {
|
if (window.location.href.indexOf('#') === -1) {
|
||||||
window.location.href = window.location.href + '#' + genKey();
|
window.location.href = window.location.href + '#' + Crypto.genKey();
|
||||||
}
|
}
|
||||||
$(window).on('hashchange', function() {
|
$(window).on('hashchange', function() {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
@ -168,20 +103,19 @@ define([
|
|||||||
}, 0);
|
}, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
var key = parseKey(window.location.hash.substring(1));
|
var key = Crypto.parseKey(window.location.hash.substring(1));
|
||||||
var channel = Nacl.util.encodeBase64(key.lookupKey).substring(0,10);
|
var myUserName = Crypto.rand64(8);
|
||||||
var myUserName = userName();
|
|
||||||
|
|
||||||
var socket = new WebSocket(Config.websocketURL);
|
var socket = new WebSocket(Config.websocketURL);
|
||||||
socket.onopen = function () {
|
socket.onopen = function () {
|
||||||
var realtime = ChainPad.create(
|
var realtime = ChainPad.create(
|
||||||
myUserName, 'x', channel, '', { transformFunction: Otaml.transform });
|
myUserName, 'x', key.channel, '', { transformFunction: Otaml.transform });
|
||||||
socket.onmessage = function (evt) {
|
socket.onmessage = function (evt) {
|
||||||
var message = decrypt(evt.data, key.cryptKey);
|
var message = Crypto.decrypt(evt.data, key.cryptKey);
|
||||||
realtime.message(message);
|
realtime.message(message);
|
||||||
};
|
};
|
||||||
realtime.onMessage(function (message) {
|
realtime.onMessage(function (message) {
|
||||||
message = encrypt(message, key.cryptKey);
|
message = Crypto.encrypt(message, key.cryptKey);
|
||||||
try {
|
try {
|
||||||
socket.send(message);
|
socket.send(message);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -193,7 +127,7 @@ define([
|
|||||||
realtime.onPatch(function () { realtimeEvent(realtime); });
|
realtime.onPatch(function () { realtimeEvent(realtime); });
|
||||||
|
|
||||||
ifrw.$('.jSTitle').html('');
|
ifrw.$('.jSTitle').html('');
|
||||||
Toolbar(ifrw.$, ifrw.$('.jSTitle'), Messages, myUserName, realtime);
|
Toolbar.create(ifrw.$('.jSTitle'), myUserName, realtime);
|
||||||
|
|
||||||
realtime.start();
|
realtime.start();
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user