Updates, NaCL
This commit is contained in:
parent
eec4c66ef6
commit
8db3885659
14 changed files with 1128 additions and 174 deletions
|
@ -1,14 +1,16 @@
|
|||
if (!localStorage.getItem('first_install_ran')) {
|
||||
localStorage.setItem('first_install_ran', 1);
|
||||
chrome.tabs.create({url: "options.html"});
|
||||
} else {
|
||||
if (isRegistrationDone()) {
|
||||
subscribeToPush(function(message) {
|
||||
console.log("Got message from " + message.source + ": \"" + getString(message.message));
|
||||
var newUnreadCount = storage.getUnencrypted("unreadCount") + 1;
|
||||
storage.putUnencrypted("unreadCount", newUnreadCount);
|
||||
chrome.browserAction.setBadgeText({text: newUnreadCount + ""});
|
||||
storeMessage(message);
|
||||
});
|
||||
registerOnLoadFunction(function() {
|
||||
if (!localStorage.getItem('first_install_ran')) {
|
||||
localStorage.setItem('first_install_ran', 1);
|
||||
chrome.tabs.create({url: "options.html"});
|
||||
} else {
|
||||
if (isRegistrationDone()) {
|
||||
subscribeToPush(function(message) {
|
||||
console.log("Got message from " + message.source + ": \"" + getString(message.message));
|
||||
var newUnreadCount = storage.getUnencrypted("unreadCount") + 1;
|
||||
storage.putUnencrypted("unreadCount", newUnreadCount);
|
||||
chrome.browserAction.setBadgeText({text: newUnreadCount + ""});
|
||||
storeMessage(message);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
174
js/helpers.js
174
js/helpers.js
|
@ -19,7 +19,9 @@ function b64ToUint6 (nChr) {
|
|||
function base64DecToArr (sBase64, nBlocksSize) {
|
||||
var
|
||||
sB64Enc = sBase64.replace(/[^A-Za-z0-9\+\/]/g, ""), nInLen = sB64Enc.length,
|
||||
nOutLen = nBlocksSize ? Math.ceil((nInLen * 3 + 1 >> 2) / nBlocksSize) * nBlocksSize : nInLen * 3 + 1 >> 2, taBytes = new Uint8Array(nOutLen);
|
||||
nOutLen = nBlocksSize ? Math.ceil((nInLen * 3 + 1 >> 2) / nBlocksSize) * nBlocksSize : nInLen * 3 + 1 >> 2;
|
||||
var aBBytes = new ArrayBuffer(nOutLen);
|
||||
var taBytes = new Uint8Array(aBBytes);
|
||||
|
||||
for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) {
|
||||
nMod4 = nInIdx & 3;
|
||||
|
@ -31,7 +33,7 @@ function base64DecToArr (sBase64, nBlocksSize) {
|
|||
nUint24 = 0;
|
||||
}
|
||||
}
|
||||
return taBytes;
|
||||
return aBBytes;
|
||||
}
|
||||
|
||||
/*********************************
|
||||
|
@ -39,20 +41,20 @@ function base64DecToArr (sBase64, nBlocksSize) {
|
|||
*********************************/
|
||||
// Strings/arrays
|
||||
var StaticByteBufferProto = new dcodeIO.ByteBuffer().__proto__;
|
||||
var StaticUint8ArrayProto = new Uint8Array().__proto__;
|
||||
var StaticArrayBufferProto = new ArrayBuffer().__proto__;
|
||||
function getString(thing) {
|
||||
if (thing.__proto__ == StaticUint8ArrayProto)
|
||||
if (thing.__proto__ == StaticArrayBufferProto)
|
||||
return String.fromCharCode.apply(null, thing);
|
||||
if (thing != undefined && thing.__proto__ == StaticByteBufferProto)
|
||||
return thing.toString("utf8");
|
||||
return thing;
|
||||
}
|
||||
|
||||
function getUint8Array(string) {
|
||||
function getArrayBuffer(string) {
|
||||
return base64DecToArr(btoa(string));
|
||||
}
|
||||
|
||||
function base64ToUint8Array(string) {
|
||||
function base64ToArrayBuffer(string) {
|
||||
return base64DecToArr(string);
|
||||
}
|
||||
|
||||
|
@ -238,15 +240,49 @@ function getDeviceObjectListFromNumber(number) {
|
|||
return deviceObjectList;
|
||||
}
|
||||
|
||||
/**********************
|
||||
*** NaCL Interface ***
|
||||
**********************/
|
||||
var onLoadCallbacks = [];
|
||||
var naclLoaded = 0;
|
||||
function registerOnLoadFunction(func) {
|
||||
if (naclLoaded)
|
||||
func();
|
||||
onLoadCallbacks[onLoadCallbacks.length] = func;
|
||||
}
|
||||
|
||||
var naclMessageNextId = 0;
|
||||
var naclMessageIdCallbackMap = {};
|
||||
function moduleDidLoad() {
|
||||
common.hideModule();
|
||||
naclLoaded = 1;
|
||||
for (var i = 0; i < onLoadCallbacks.length; i++)
|
||||
onLoadCallbacks[i]();
|
||||
onLoadCallbacks = [];
|
||||
}
|
||||
|
||||
function handleMessage(message) {
|
||||
console.log("Got message");
|
||||
console.log(message);
|
||||
naclMessageIdCallbackMap[message.data.call_id](message.data);
|
||||
}
|
||||
|
||||
function postNaclMessage(message, callback) {
|
||||
naclMessageIdCallbackMap[naclMessageNextId] = callback;
|
||||
message.call_id = naclMessageNextId++;
|
||||
common.naclModule.postMessage(message);
|
||||
}
|
||||
|
||||
/*******************************************
|
||||
*** Utilities to manage keys/randomness ***
|
||||
*******************************************/
|
||||
function getRandomBytes(size) {
|
||||
//TODO: Better random (https://www.grc.com/r&d/js.htm?)
|
||||
try {
|
||||
var array = new Uint8Array(size);
|
||||
var buffer = new ArrayBuffer(size);
|
||||
var array = new Uint8Array(buffer);
|
||||
window.crypto.getRandomValues(array);
|
||||
return array;
|
||||
return buffer;
|
||||
} catch (err) {
|
||||
//TODO: ummm...wat?
|
||||
throw err;
|
||||
|
@ -254,23 +290,26 @@ function getRandomBytes(size) {
|
|||
}
|
||||
|
||||
(function(crypto, $, undefined) {
|
||||
var createNewKeyPair = function() {
|
||||
var createNewKeyPair = function(callback) {
|
||||
//TODO
|
||||
var privKey = getRandomBytes(32);
|
||||
privKey[0] &= 248;
|
||||
privKey[31] &= 127;
|
||||
privKey[31] |= 64;
|
||||
var pubKey = "BRTJzsHPUWRRBxyo5MoaBRidMk2fwDlfqvU91b6pzbED";
|
||||
var privKey = "";
|
||||
return { pubKey: pubKey, privKey: privKey };
|
||||
postNaclMessage({command: "bytesToPriv", priv: privKey}, function(message) {
|
||||
postNaclMessage({command: "privToPub", priv: message.res}, function(message) {
|
||||
callback({ pubKey: message.res, privKey: privKey });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var crypto_storage = {};
|
||||
|
||||
crypto_storage.getNewPubKeySTORINGPrivKey = function(keyName) {
|
||||
var keyPair = createNewKeyPair();
|
||||
storage.putEncrypted("25519Key" + keyName, keyPair);
|
||||
return keyPair.pubKey;
|
||||
crypto_storage.getNewPubKeySTORINGPrivKey = function(keyName, callback) {
|
||||
createNewKeyPair(function(keyPair) {
|
||||
storage.putEncrypted("25519Key" + keyName, keyPair);
|
||||
callback(keyPair.pubKey);
|
||||
});
|
||||
}
|
||||
|
||||
crypto_storage.getStoredPubKey = function(keyName) {
|
||||
|
@ -379,7 +418,7 @@ function getRandomBytes(size) {
|
|||
chain.chainKey.counter = counter;
|
||||
}
|
||||
|
||||
var maybeStepRatchet = function(session, remoteKey, previousCounter) {
|
||||
var maybeStepRatchet = function(session, remoteKey, previousCounter, callback) {
|
||||
if (sesion[remoteKey] !== undefined) //TODO: null???
|
||||
return;
|
||||
|
||||
|
@ -397,12 +436,16 @@ function getRandomBytes(size) {
|
|||
var masterKey = HKDF(ECDHE(remoteKey, ratchet.ephemeralKeyPair.privKey), ratchet.rootKey, "WhisperRatchet");
|
||||
session[remoteKey] = { messageKeys: {}, chainKey: { counter: 0, key: masterKey.substring(32, 64) } };
|
||||
|
||||
ratchet.ephemeralKeyPair = createNewKeyPair();
|
||||
masterKey = HKDF(ECDHE(remoteKey, ratchet.ephemeralKeyPair.privKey), masterKey.substring(0, 32), "WhisperRatchet");
|
||||
ratchet.rootKey = masterKey.substring(0, 32);
|
||||
session[nextRatchet.ephemeralKeyPair.pubKey] = { messageKeys: {}, chainKey: { counter: 0, key: masterKey.substring(32, 64) } };
|
||||
createNewKeyPair(function(keyPair) {
|
||||
ratchet.ephemeralKeyPair = keyPair;
|
||||
|
||||
ratchet.lastRemoteEphemeralKey = remoteKey;
|
||||
masterKey = HKDF(ECDHE(remoteKey, ratchet.ephemeralKeyPair.privKey), masterKey.substring(0, 32), "WhisperRatchet");
|
||||
ratchet.rootKey = masterKey.substring(0, 32);
|
||||
session[nextRatchet.ephemeralKeyPair.pubKey] = { messageKeys: {}, chainKey: { counter: 0, key: masterKey.substring(32, 64) } };
|
||||
|
||||
ratchet.lastRemoteEphemeralKey = remoteKey;
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
var doDecryptWhisperMessage = function(ciphertext, mac, messageKey, counter) {
|
||||
|
@ -414,7 +457,7 @@ function getRandomBytes(size) {
|
|||
}
|
||||
|
||||
// returns decrypted protobuf
|
||||
var decryptWhisperMessage = function(encodedNumber, messageBytes) {
|
||||
var decryptWhisperMessage = function(encodedNumber, messageBytes, callback) {
|
||||
var session = crypto_storage.getSession(encodedNumber);
|
||||
if (session === undefined)
|
||||
throw "No session currently open with " + encodedNumber;
|
||||
|
@ -427,18 +470,19 @@ function getRandomBytes(size) {
|
|||
|
||||
var message = decodeWhisperMessageProtobuf(messageProto);
|
||||
|
||||
maybeStepRatchet(session, getString(message.ephemeralKey), message.previousCounter);
|
||||
var chain = session[getString(message.ephemeralKey)];
|
||||
maybeStepRatchet(session, getString(message.ephemeralKey), message.previousCounter, function() {
|
||||
var chain = session[getString(message.ephemeralKey)];
|
||||
|
||||
fillMessageKeys(chain, message.counter);
|
||||
fillMessageKeys(chain, message.counter);
|
||||
|
||||
var plaintext = doDecryptWhisperMessage(message.ciphertext, mac, chain.messageKeys[message.counter], message.counter);
|
||||
delete chain.messageKeys[message.counter];
|
||||
var plaintext = doDecryptWhisperMessage(message.ciphertext, mac, chain.messageKeys[message.counter], message.counter);
|
||||
delete chain.messageKeys[message.counter];
|
||||
|
||||
removeOldChains(session);
|
||||
removeOldChains(session);
|
||||
|
||||
crypto_storage.saveSession(encodedNumber, session);
|
||||
return decodePushMessageContentProtobuf(atob(plaintext));
|
||||
crypto_storage.saveSession(encodedNumber, session);
|
||||
callback(decodePushMessageContentProtobuf(atob(plaintext)));
|
||||
});
|
||||
}
|
||||
|
||||
/*************************
|
||||
|
@ -477,18 +521,18 @@ function getRandomBytes(size) {
|
|||
return atob(plaintext.toString(CryptoJS.enc.Base64));
|
||||
}
|
||||
|
||||
crypto.handleIncomingPushMessageProto = function(proto) {
|
||||
crypto.handleIncomingPushMessageProto = function(proto, callback) {
|
||||
switch(proto.type) {
|
||||
case 0: //TYPE_MESSAGE_PLAINTEXT
|
||||
proto.message = decodePushMessageContentProtobuf(getString(proto.message));
|
||||
callback(decodePushMessageContentProtobuf(getString(proto.message)));
|
||||
break;
|
||||
case 1: //TYPE_MESSAGE_CIPHERTEXT
|
||||
proto.message = decryptWhisperMessage(proto.source, getString(proto.message));
|
||||
decryptWhisperMessage(proto.source, getString(proto.message), function(result) { callback(result); });
|
||||
break;
|
||||
case 3: //TYPE_MESSAGE_PREKEY_BUNDLE
|
||||
var preKeyProto = decodePreKeyWhisperMessageProtobuf(getString(proto.message));
|
||||
initSessionFromPreKeyWhisperMessage(proto.source, preKeyProto);
|
||||
proto.message = decryptWhisperMessage(proto.source, getString(preKeyProto.message));
|
||||
decryptWhisperMessage(proto.source, getString(preKeyProto.message), function(result) { callback(result); });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -499,26 +543,42 @@ function getRandomBytes(size) {
|
|||
}
|
||||
|
||||
var GENERATE_KEYS_KEYS_GENERATED = 100;
|
||||
crypto.generateKeys = function() {
|
||||
crypto.generateKeys = function(callback) {
|
||||
var identityKey = crypto_storage.getStoredPubKey("identityKey");
|
||||
var identityKeyCalculated = function(pubKey) {
|
||||
identityKey = pubKey;
|
||||
|
||||
var firstKeyId = storage.getEncrypted("maxPreKeyId", -1) + 1;
|
||||
storage.putEncrypted("maxPreKeyId", firstKeyId + GENERATE_KEYS_KEYS_GENERATED);
|
||||
|
||||
if (firstKeyId > 16777000)
|
||||
throw "You crazy motherfucker";
|
||||
|
||||
var keys = {};
|
||||
keys.keys = [];
|
||||
var keysLeft = GENERATE_KEYS_KEYS_GENERATED;
|
||||
for (var i = firstKeyId; i < firstKeyId + GENERATE_KEYS_KEYS_GENERATED; i++) {
|
||||
crypto_storage.getNewPubKeySTORINGPrivKey("preKey" + i, function(pubKey) {
|
||||
keys.keys[i] = {keyId: i, publicKey: pubKey, identityKey: identityKey};
|
||||
keysLeft--;
|
||||
if (keysLeft == 0) {
|
||||
// 0xFFFFFF == 16777215
|
||||
keys.lastResortKey = {keyId: 16777215, publicKey: crypto_storage.getStoredPubKey("preKey16777215"), identityKey: identityKey};//TODO: Rotate lastResortKey
|
||||
if (keys.lastResortKey.publicKey === undefined) {
|
||||
crypto_storage.getNewPubKeySTORINGPrivKey("preKey16777215", function(pubKey) {
|
||||
keys.lastResortKey.publicKey = pubKey;
|
||||
callback(keys);
|
||||
});
|
||||
} else
|
||||
callback(keys);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (identityKey === undefined)
|
||||
identityKey = crypto_storage.getNewPubKeySTORINGPrivKey("identityKey"); //TODO: should probably just throw?
|
||||
|
||||
var firstKeyId = storage.getEncrypted("maxPreKeyId", -1) + 1;
|
||||
storage.putEncrypted("maxPreKeyId", firstKeyId + GENERATE_KEYS_KEYS_GENERATED);
|
||||
|
||||
if (firstKeyId > 16777000)
|
||||
throw "You crazy motherfucker";
|
||||
|
||||
var keys = {};
|
||||
keys.keys = [];
|
||||
for (var i = firstKeyId; i < firstKeyId + GENERATE_KEYS_KEYS_GENERATED; i++)
|
||||
keys.keys[i] = {keyId: i, publicKey: crypto_storage.getNewPubKeySTORINGPrivKey("preKey" + i), identityKey: identityKey};
|
||||
// 0xFFFFFF == 16777215
|
||||
keys.lastResortKey = {keyId: 16777215, publicKey: crypto_storage.getStoredPubKey("preKey16777215"), identityKey: identityKey};//TODO: Rotate lastResortKey
|
||||
if (keys.lastResortKey.publicKey === undefined)
|
||||
keys.lastResortKey.publicKey = crypto_storage.getNewPubKeySTORINGPrivKey("preKey16777215");
|
||||
return keys;
|
||||
crypto_storage.getNewPubKeySTORINGPrivKey("identityKey", function(pubKey) { identityKeyCalculated(pubKey); });
|
||||
else
|
||||
identityKeyCalculated(pubKey);
|
||||
}
|
||||
|
||||
}( window.crypto = window.crypto || {}, jQuery ));
|
||||
|
@ -621,9 +681,9 @@ function subscribeToPush(message_callback) {
|
|||
}
|
||||
|
||||
try {
|
||||
crypto.handleIncomingPushMessageProto(proto); // Decrypts/decodes/fills in fields/etc
|
||||
|
||||
message_callback(proto);
|
||||
crypto.handleIncomingPushMessageProto(proto, function(decrypted) {
|
||||
message_callback(decrypted);
|
||||
}); // Decrypts/decodes/fills in fields/etc
|
||||
} catch (e) {
|
||||
//TODO: Tell the user decryption failed
|
||||
}
|
||||
|
@ -739,8 +799,8 @@ function sendMessageToNumbers(numbers, message, success_callback, error_callback
|
|||
}, error_callback);
|
||||
}
|
||||
|
||||
|
||||
function requestIdentityPrivKeyFromMasterDevice(number, identityKey) {
|
||||
sendMessageToDevices([getDeviceObject(getNumberFromString(number)) + ".1"],
|
||||
{message: "Identity Key request"}, function() {}, function() {});//TODO
|
||||
}
|
||||
|
||||
|
|
|
@ -74,17 +74,18 @@ $('#init-go').click(function() {
|
|||
|
||||
var register_keys_func = function() {
|
||||
$('#verify2done').html('done');
|
||||
var keys = crypto.generateKeys();
|
||||
$('#verify3done').html('done');
|
||||
doAjax({call: 'keys', httpType: 'PUT', do_auth: true, jsonData: keys,
|
||||
success_callback: function(response) {
|
||||
$('#complete-number').html(number);
|
||||
$('#verify').hide();
|
||||
$('#setup-complete').show();
|
||||
registrationDone();
|
||||
}, error_callback: function(code) {
|
||||
alert(code); //TODO
|
||||
}
|
||||
crypto.generateKeys(function(keys) {
|
||||
$('#verify3done').html('done');
|
||||
doAjax({call: 'keys', httpType: 'PUT', do_auth: true, jsonData: keys,
|
||||
success_callback: function(response) {
|
||||
$('#complete-number').html(number);
|
||||
$('#verify').hide();
|
||||
$('#setup-complete').show();
|
||||
registrationDone();
|
||||
}, error_callback: function(code) {
|
||||
alert(code); //TODO
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -120,9 +121,11 @@ $('#init-go').click(function() {
|
|||
}
|
||||
});
|
||||
|
||||
if (!isRegistrationDone()) {
|
||||
$('#init-setup').show();
|
||||
} else {
|
||||
$('#complete-number').html(storage.getUnencrypted("number_id").split(".")[0]);
|
||||
$('#setup-complete').show();
|
||||
}
|
||||
registerOnLoadFunction(function() {
|
||||
if (!isRegistrationDone()) {
|
||||
$('#init-setup').show();
|
||||
} else {
|
||||
$('#complete-number').html(storage.getUnencrypted("number_id").split(".")[0]);
|
||||
$('#setup-complete').show();
|
||||
}
|
||||
});
|
||||
|
|
98
js/popup.js
98
js/popup.js
|
@ -7,55 +7,57 @@ $('#send_link').onclick = function() {
|
|||
$('#send').show();
|
||||
}
|
||||
|
||||
if (storage.getUnencrypted("number_id") === undefined) {
|
||||
chrome.tabs.create({url: "options.html"});
|
||||
} else {
|
||||
function fillMessages() {
|
||||
var MAX_MESSAGES_PER_CONVERSATION = 4;
|
||||
var MAX_CONVERSATIONS = 5;
|
||||
registerOnLoadFunction(function() {
|
||||
if (storage.getUnencrypted("number_id") === undefined) {
|
||||
chrome.tabs.create({url: "options.html"});
|
||||
} else {
|
||||
function fillMessages() {
|
||||
var MAX_MESSAGES_PER_CONVERSATION = 4;
|
||||
var MAX_CONVERSATIONS = 5;
|
||||
|
||||
var conversations = [];
|
||||
var conversations = [];
|
||||
|
||||
var messageMap = getMessageMap();
|
||||
for (conversation in messageMap) {
|
||||
var messages = messageMap[conversation];
|
||||
messages.sort(function(a, b) { return b.timestamp - a.timestamp; });
|
||||
conversations[conversations.length] = messages;
|
||||
}
|
||||
|
||||
conversations.sort(function(a, b) { return b[0].timestamp - a[0].timestamp });
|
||||
|
||||
var ul = $('#messages');
|
||||
ul.html('');
|
||||
for (var i = 0; i < MAX_CONVERSATIONS && i < conversations.length; i++) {
|
||||
var conversation = conversations[i];
|
||||
ul.append('<li>');
|
||||
for (var j = 0; j < MAX_MESSAGES_PER_CONVERSATION && j < conversation.length; j++) {
|
||||
var message = conversation[j];
|
||||
ul.append("From: " + message.sender + ", at: " + timestampToHumanReadable(message.timestamp) + "<br>");
|
||||
ul.append("Message: " + message.message + "<br><br>");
|
||||
var messageMap = getMessageMap();
|
||||
for (conversation in messageMap) {
|
||||
var messages = messageMap[conversation];
|
||||
messages.sort(function(a, b) { return b.timestamp - a.timestamp; });
|
||||
conversations[conversations.length] = messages;
|
||||
}
|
||||
ul.append("<input type='text' id=text" + i + " /><button id=button" + i + ">Send</button><br>");
|
||||
$('#button' + i).click(function() {
|
||||
var sendDestinations = [conversation[0].sender];
|
||||
for (var j = 0; j < conversation[0].destinations.length; j++)
|
||||
sendDestinations[sendDestinations.length] = conversation[0].destinations[j];
|
||||
sendMessageToNumbers(sendDestinations, { message: $('#text' + i).val() }, function(result) {
|
||||
console.log("Sent message: " + JSON.stringify(result));
|
||||
}, function(error_msg) {
|
||||
alert(error_msg); //TODO
|
||||
});
|
||||
});
|
||||
ul.append('</li>');
|
||||
}
|
||||
}
|
||||
|
||||
$(window).bind('storage', function(e) {
|
||||
console.log("Got localStorage update for key " + e.key);
|
||||
if (event.key == "emessageMap")//TODO: Fix when we get actual encryption
|
||||
fillMessages();
|
||||
});
|
||||
fillMessages();
|
||||
storage.putUnencrypted("unreadCount", 0);
|
||||
chrome.browserAction.setBadgeText({text: ""});
|
||||
}
|
||||
conversations.sort(function(a, b) { return b[0].timestamp - a[0].timestamp });
|
||||
|
||||
var ul = $('#messages');
|
||||
ul.html('');
|
||||
for (var i = 0; i < MAX_CONVERSATIONS && i < conversations.length; i++) {
|
||||
var conversation = conversations[i];
|
||||
ul.append('<li>');
|
||||
for (var j = 0; j < MAX_MESSAGES_PER_CONVERSATION && j < conversation.length; j++) {
|
||||
var message = conversation[j];
|
||||
ul.append("From: " + message.sender + ", at: " + timestampToHumanReadable(message.timestamp) + "<br>");
|
||||
ul.append("Message: " + message.message + "<br><br>");
|
||||
}
|
||||
ul.append("<input type='text' id=text" + i + " /><button id=button" + i + ">Send</button><br>");
|
||||
$('#button' + i).click(function() {
|
||||
var sendDestinations = [conversation[0].sender];
|
||||
for (var j = 0; j < conversation[0].destinations.length; j++)
|
||||
sendDestinations[sendDestinations.length] = conversation[0].destinations[j];
|
||||
sendMessageToNumbers(sendDestinations, { message: $('#text' + i).val() }, function(result) {
|
||||
console.log("Sent message: " + JSON.stringify(result));
|
||||
}, function(error_msg) {
|
||||
alert(error_msg); //TODO
|
||||
});
|
||||
});
|
||||
ul.append('</li>');
|
||||
}
|
||||
}
|
||||
|
||||
$(window).bind('storage', function(e) {
|
||||
console.log("Got localStorage update for key " + e.key);
|
||||
if (event.key == "emessageMap")//TODO: Fix when we get actual encryption
|
||||
fillMessages();
|
||||
});
|
||||
fillMessages();
|
||||
storage.putUnencrypted("unreadCount", 0);
|
||||
chrome.browserAction.setBadgeText({text: ""});
|
||||
}
|
||||
});
|
||||
|
|
65
js/test.js
65
js/test.js
|
@ -1,37 +1,62 @@
|
|||
// Setup dumb test wrapper
|
||||
var testsdiv = $('#tests');
|
||||
var testsOutstanding = [];
|
||||
function TEST(func, name) {
|
||||
var funcName = name === undefined ? func + "" : name;
|
||||
try {
|
||||
if (func())
|
||||
var testIndex = testsOutstanding.length;
|
||||
function callback(result) {
|
||||
if (result)
|
||||
testsdiv.append('<p style="color: green;">' + funcName + ' passed</p>');
|
||||
else
|
||||
testsdiv.append('<p style="color: red;">' + funcName + ' returned false</p>');
|
||||
delete testsOutstanding[testIndex];
|
||||
}
|
||||
try {
|
||||
testsOutstanding[testIndex] = funcName;
|
||||
func(callback);
|
||||
} catch (e) {
|
||||
testsdiv.append('<p style="color: red;">' + funcName + ' threw ' + e + '</p>');
|
||||
}
|
||||
}
|
||||
|
||||
// Random tests to check my JS knowledge
|
||||
TEST(function() { return !objectContainsKeys({}); });
|
||||
TEST(function() { return objectContainsKeys({ a: undefined }); });
|
||||
TEST(function() { return objectContainsKeys({ a: null }); });
|
||||
registerOnLoadFunction(function() {
|
||||
localStorage.clear();
|
||||
|
||||
// Basic sanity-checks on the crypto library
|
||||
TEST(function() {
|
||||
var PushMessageProto = dcodeIO.ProtoBuf.loadProtoFile("IncomingPushMessageSignal.proto").build("textsecure.PushMessageContent");
|
||||
var IncomingMessageProto = dcodeIO.ProtoBuf.loadProtoFile("IncomingPushMessageSignal.proto").build("textsecure.IncomingPushMessageSignal");
|
||||
// Random tests to check my JS knowledge
|
||||
TEST(function(callback) { callback(!objectContainsKeys({})); });
|
||||
TEST(function(callback) { callback(objectContainsKeys({ a: undefined })); });
|
||||
TEST(function(callback) { callback(objectContainsKeys({ a: null })); });
|
||||
|
||||
var text_message = new PushMessageProto();
|
||||
text_message.body = "Hi Mom";
|
||||
var server_message = {type: 0, // unencrypted
|
||||
source: "+19999999999", timestamp: 42, message: text_message.encode() };
|
||||
// Basic sanity-checks on the crypto library
|
||||
TEST(function(callback) {
|
||||
var PushMessageProto = dcodeIO.ProtoBuf.loadProtoFile("protos/IncomingPushMessageSignal.proto").build("textsecure.PushMessageContent");
|
||||
var IncomingMessageProto = dcodeIO.ProtoBuf.loadProtoFile("protos/IncomingPushMessageSignal.proto").build("textsecure.IncomingPushMessageSignal");
|
||||
|
||||
crypto.handleIncomingPushMessageProto(server_message);
|
||||
return server_message.message.body == text_message.body &&
|
||||
server_message.message.attachments.length == text_message.attachments.length &&
|
||||
text_message.attachments.length == 0;
|
||||
}, 'Unencrypted PushMessageProto "decrypt"');
|
||||
var text_message = new PushMessageProto();
|
||||
text_message.body = "Hi Mom";
|
||||
var server_message = {type: 0, // unencrypted
|
||||
source: "+19999999999", timestamp: 42, message: text_message.encode() };
|
||||
|
||||
// TODO: Run through the test vectors for the axolotl ratchet
|
||||
crypto.handleIncomingPushMessageProto(server_message, function(message) {
|
||||
callback(message.body == text_message.body &&
|
||||
message.attachments.length == text_message.attachments.length &&
|
||||
text_message.attachments.length == 0);
|
||||
});
|
||||
}, 'Unencrypted PushMessageProto "decrypt"');
|
||||
|
||||
TEST(function(callback) {
|
||||
crypto.generateKeys(function() {
|
||||
callback(true);
|
||||
});
|
||||
}, "Test simple create key");
|
||||
|
||||
// TODO: Run through the test vectors for the axolotl ratchet
|
||||
|
||||
window.setTimeout(function() {
|
||||
for (var i = 0; i < testsOutstanding.length; i++)
|
||||
if (testsOutstanding[i] !== undefined)
|
||||
testsdiv.append('<p style="color: red;">' + testsOutstanding[i] + ' timed out</p>');
|
||||
|
||||
localStorage.clear();
|
||||
}, 1000);
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue