Things:
* key API changes moxie made because he disliked the other API * remove atmosphere * Fix some bugs in the send path, update for new send API * Send HTML
This commit is contained in:
parent
000a5e1440
commit
136a8941c1
8 changed files with 182 additions and 3070 deletions
|
@ -2,7 +2,6 @@
|
|||
<head>
|
||||
<script type="text/javascript" src="js-deps/nacl-common.js"></script>
|
||||
<script type="text/javascript" src="js-deps/jquery.js"></script>
|
||||
<script type="text/javascript" src="js-deps/jquery.atmosphere.js"></script>
|
||||
<script type="text/javascript" src="js-deps/core.js"></script>
|
||||
<script type="text/javascript" src="js-deps/enc-base64.js"></script>
|
||||
<script type="text/javascript" src="js-deps/cipher-core.js"></script>
|
||||
|
@ -17,7 +16,6 @@
|
|||
<script type="text/javascript" src="js-deps/ProtoBuf.min.js"></script>
|
||||
<script type="text/javascript" src="js/helpers.js"></script>
|
||||
<script type="text/javascript" src="js/api.js"></script>
|
||||
<script type="text/javascript" src="js/fake_api.js"></script>
|
||||
<script type="text/javascript" src="js/background.js"></script>
|
||||
</head>
|
||||
<body data-name="curve25519" data-tools="pnacl" data-configs="Debug Release" data-path="pnacl/{config}">
|
||||
|
|
File diff suppressed because it is too large
Load diff
30
js/api.js
30
js/api.js
|
@ -7,8 +7,8 @@ var URL_CALLS = {};
|
|||
URL_CALLS['accounts'] = "/v1/accounts";
|
||||
URL_CALLS['devices'] = "/v1/devices";
|
||||
URL_CALLS['keys'] = "/v1/keys";
|
||||
URL_CALLS['push'] = "/v1/messagesocket";
|
||||
URL_CALLS['messages'] = "/v1/messages/";
|
||||
URL_CALLS['push'] = "/v1/websocket";
|
||||
URL_CALLS['messages'] = "/v1/messages";
|
||||
|
||||
var API = new function() {
|
||||
|
||||
|
@ -119,16 +119,34 @@ var API = new function() {
|
|||
call : 'keys',
|
||||
httpType : 'GET',
|
||||
do_auth : true,
|
||||
urlParameters : "/" + getNumberFromString(number) + "?multikeys",
|
||||
success_callback : success_callback,
|
||||
urlParameters : "/" + getNumberFromString(number) + "/*",
|
||||
success_callback : function(response) {
|
||||
//TODO: Do this conversion somewhere else?
|
||||
var res = response.keys;
|
||||
for (var i = 0; i < res.length; i++) {
|
||||
res[i].identityKey = base64DecToArr(res[i].identityKey);
|
||||
res[i].publicKey = base64DecToArr(res[i].publicKey);
|
||||
if (res[i].keyId === undefined)
|
||||
res[i].keyId = 0;
|
||||
}
|
||||
success_callback(res);
|
||||
},
|
||||
error_callback : error_callback
|
||||
});
|
||||
};
|
||||
|
||||
this.sendMessages = function(jsonData, success_callback, error_callback) {
|
||||
this.sendMessages = function(destination, messageArray, success_callback, error_callback) {
|
||||
//TODO: Do this conversion somewhere else?
|
||||
for (var i = 0; i < messageArray.length; i++)
|
||||
messageArray[i].body = btoa(messageArray[i].body);
|
||||
var jsonData = { messages: messageArray };
|
||||
if (messageArray[0].relay !== undefined)
|
||||
jsonData.relay = messageArray[0].relay;
|
||||
|
||||
this.doAjax({
|
||||
call : 'messages',
|
||||
httpType : 'POST',
|
||||
httpType : 'PUT',
|
||||
urlParameters : '/' + destination,
|
||||
do_auth : true,
|
||||
jsonData : jsonData,
|
||||
success_callback : success_callback,
|
||||
|
|
228
js/helpers.js
228
js/helpers.js
|
@ -206,6 +206,11 @@ function getEncodedNumber(number) {
|
|||
return number;
|
||||
}
|
||||
|
||||
function verifyNumber(string) {
|
||||
//TODO: fancy country-code guessing and number verification
|
||||
return getEncodedNumber(string.trim());
|
||||
}
|
||||
|
||||
function getDeviceId(encodedNumber) {
|
||||
var split = encodedNumber.split(".");
|
||||
if (split.length > 1)
|
||||
|
@ -865,51 +870,51 @@ var crypto_tests = {};
|
|||
function subscribeToPush(message_callback) {
|
||||
var user = storage.getUnencrypted("number_id");
|
||||
var password = storage.getEncrypted("password");
|
||||
var request = { url: URL_BASE + URL_CALLS['push'] + "/?user=%2B" + getString(user).substring(1) + "&password=" + getString(password),
|
||||
method: 'GET',
|
||||
fallbackMethod: 'GET',
|
||||
transport: 'websocket',
|
||||
fallbackTransport: 'websocket',
|
||||
logLevel: 'debug', //TODO
|
||||
trackMessageLength: false,
|
||||
//data: "user=" + getString(user) + "&password=" + getString(password),
|
||||
onOpen: function(response) {
|
||||
console.log('Connected to server using ' + response.transport);
|
||||
},
|
||||
onMessage: function(response) {
|
||||
try {
|
||||
// Some bug in Atmosphere.js is forcing trackMessageLength to true
|
||||
var message = JSON.parse(response.responseBody.split("|")[1]);
|
||||
} catch (e) {
|
||||
console.log('Error parsing server JSON message: ' + response.responseBody.split("|")[1]);
|
||||
return;
|
||||
}
|
||||
var URL = URL_BASE.replace(/^http:/g, "ws:").replace(/^https:/g, "wss:") + URL_CALLS['push'] + "/?user=%2B" + getString(user).substring(1) + "&password=" + getString(password);
|
||||
var socket = new WebSocket(URL);
|
||||
|
||||
var proto;
|
||||
try {
|
||||
var plaintext = crypto.decryptWebsocketMessage(message.message);
|
||||
var proto = decodeIncomingPushMessageProtobuf(plaintext);
|
||||
// After this point, a) decoding errors are not the server's fault, and
|
||||
// b) we should handle them gracefully and tell the user they received an invalid message
|
||||
API.pushMessage(message.id);
|
||||
} catch (e) {
|
||||
console.log("Error decoding message: " + e);
|
||||
return;
|
||||
}
|
||||
//TODO: GUI
|
||||
socket.onerror = function(socketEvent) {
|
||||
console.log('Server is down :(');
|
||||
setTimeout(function() { subscribeToPush(message_callback); }, 1000);
|
||||
};
|
||||
socket.onclose = function(socketEvent) {
|
||||
console.log('Server closed :(');
|
||||
setTimeout(function() { subscribeToPush(message_callback); }, 1000);
|
||||
};
|
||||
socket.onopen = function(socketEvent) {
|
||||
console.log('Connected to server!');
|
||||
};
|
||||
|
||||
try {
|
||||
crypto.handleIncomingPushMessageProto(proto, function(decrypted) {
|
||||
message_callback(decrypted);
|
||||
}); // Decrypts/decodes/fills in fields/etc
|
||||
} catch (e) {
|
||||
//TODO: Tell the user decryption failed
|
||||
}
|
||||
},
|
||||
onError: function(response) {
|
||||
console.log('Server is down :(');
|
||||
//TODO: GUI
|
||||
}};
|
||||
$.atmosphere.subscribe(request);
|
||||
socket.onmessage = function(response) {
|
||||
try {
|
||||
// Some bug in Atmosphere.js is forcing trackMessageLength to true
|
||||
var message = JSON.parse(response.responseBody.split("|")[1]);
|
||||
} catch (e) {
|
||||
console.log('Error parsing server JSON message: ' + response.responseBody.split("|")[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
var proto;
|
||||
try {
|
||||
var plaintext = crypto.decryptWebsocketMessage(message.message);
|
||||
var proto = decodeIncomingPushMessageProtobuf(plaintext);
|
||||
// After this point, a) decoding errors are not the server's fault, and
|
||||
// b) we should handle them gracefully and tell the user they received an invalid message
|
||||
API.pushMessage(message.id);
|
||||
} catch (e) {
|
||||
console.log("Error decoding message: " + e);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
crypto.handleIncomingPushMessageProto(proto, function(decrypted) {
|
||||
message_callback(decrypted);
|
||||
}); // Decrypts/decodes/fills in fields/etc
|
||||
} catch (e) {
|
||||
//TODO: Tell the user decryption failed
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// success_callback(identity_key), error_callback(error_msg)
|
||||
|
@ -937,83 +942,98 @@ function getKeysForNumber(number, success_callback, error_callback) {
|
|||
|
||||
// success_callback(server success/failure map), error_callback(error_msg)
|
||||
// message == PushMessageContentProto (NOT STRING)
|
||||
function sendMessageToDevices(deviceObjectList, message, success_callback, error_callback) {
|
||||
function sendMessageToDevices(number, deviceObjectList, message, success_callback, error_callback) {
|
||||
var jsonData = [];
|
||||
for (var i = 0; i < deviceObjectList.legnth; i++) {
|
||||
var encryptedMsg = encryptMessageFor(deviceObjectList[i], message);
|
||||
jsonData[jsonData.length] = {
|
||||
type: encryptedMsg.type,
|
||||
destination: deviceObjectList[i].encodedNumber,
|
||||
body: encryptedMsg.body,
|
||||
relay: deviceObjectList[i].relay,
|
||||
timestamp: new Date().getTime()
|
||||
};
|
||||
//TODO: need to encrypt with session key?
|
||||
var relay = undefined;
|
||||
|
||||
var doSend = function() {
|
||||
API.sendMessages(number, jsonData,
|
||||
function(result) {
|
||||
success_callback(result);
|
||||
}, function(code) {
|
||||
error_callback(code);
|
||||
}
|
||||
);
|
||||
}
|
||||
API.sendMessages(jsonData,
|
||||
function(result) {
|
||||
if (result.missingDeviceIds.length > 0) {
|
||||
var responsesLeft = result.missingDeviceIds.length;
|
||||
var errorThrown = 0;
|
||||
for (var i = 0; i < result.missingDeviceIds.length; i++) {
|
||||
getKeysForNumber(result.missingDeviceIds[i], function(identity_key) {
|
||||
responsesLeft--;
|
||||
if (responsesLeft == 0 && errorThrown == 0)
|
||||
sendMessageToDevices(deviceObjectList, message, success_callback, error_callback);
|
||||
}, function(error_msg) {
|
||||
errorThrown++;
|
||||
if (errorThrown == 1)
|
||||
error_callback("Failed to retreive new device keys for number " + result.missingDeviceIds[i]);
|
||||
});
|
||||
|
||||
var addEncryptionFor;
|
||||
addEncryptionFor = function(i) {
|
||||
crypto.encryptMessageFor(deviceObjectList[i], message, function(encryptedMsg) {
|
||||
jsonData[i] = {
|
||||
type: encryptedMsg.type,
|
||||
destination: deviceObjectList[i].encodedNumber,
|
||||
body: encryptedMsg.body,
|
||||
timestamp: new Date().getTime()
|
||||
};
|
||||
|
||||
if (deviceObjectList[i].relay !== undefined) {
|
||||
jsonData[i].relay = deviceObjectList[i].relay;
|
||||
if (relay === undefined)
|
||||
relay = jsonData[i].relay;
|
||||
else if (relay != jsonData[i].relay) {
|
||||
error_callback("Mismatched relays for number " + number);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
success_callback(result);
|
||||
if (relay === undefined)
|
||||
relay = "";
|
||||
else if (relay != "") {
|
||||
error_callback("Mismatched relays for number " + number);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}, function(code) {
|
||||
error_callback("Failed to conect to data channel: " + code);
|
||||
}
|
||||
);
|
||||
|
||||
if (i+1 < deviceObjectList.length)
|
||||
addEncryptionFor(i+1);
|
||||
else
|
||||
doSend();
|
||||
});
|
||||
//TODO: need to encrypt with session key?
|
||||
}
|
||||
addEncryptionFor(0);
|
||||
}
|
||||
|
||||
// success_callback(success/failure map, see second-to-last line), error_callback(error_msg)
|
||||
function sendMessageToNumbers(numbers, message, success_callback, error_callback) {
|
||||
var deviceObjectList = [];
|
||||
// callback(success/failure map, see code)
|
||||
// message == PushMessageContentProto (NOT STRING)
|
||||
function sendMessageToNumbers(numbers, message, callback) {
|
||||
var numbersCompleted = 0;
|
||||
var errors = [];
|
||||
var successfulNumbers = [];
|
||||
|
||||
var numberCompleted = function() {
|
||||
numbersCompleted++;
|
||||
if (numbersCompleted >= numbers.length)
|
||||
callback({success: successfulNumbers, failure: errors});
|
||||
}
|
||||
|
||||
var registerError = function(number, message) {
|
||||
errors[errors.length] = { number: number, reason: message };
|
||||
numberCompleted();
|
||||
}
|
||||
|
||||
var doSendMessage = function(number, devicesForNumber, message) {
|
||||
sendMessageToDevices(number, devicesForNumber, message, function(result) {
|
||||
successfulNumbers[successfulNumbers.length] = number;
|
||||
numberCompleted();
|
||||
}, function(error_code) {
|
||||
//TODO: Re-request keys for number here
|
||||
if (error_code == 410 || error_code == 409) {}
|
||||
registerError(number, message);
|
||||
});
|
||||
}
|
||||
|
||||
var deviceDatasMissing = 0;
|
||||
var loopDone = 0;
|
||||
var errorThrown = 0;
|
||||
for (var i = 0; i < numbers.length; i++) {
|
||||
var devicesForNumber = getDeviceObjectListFromNumber(numbers[i]);
|
||||
for (var j = 0; j < devicesForNumber.length; j++)
|
||||
deviceObjectList[deviceObjectList.length] = devicesForNumber[j];
|
||||
|
||||
if (devicesForNumber.length == 0) {
|
||||
deviceDatasMissing++;
|
||||
getKeysForNumber(numbers[i], function(identity_key) {
|
||||
deviceDatasMissing--;
|
||||
if (deviceDatasMissing == 0 && loopDone && errorThrown == 0)
|
||||
sendMessageToNumbers(numbers, message, success_callback, error_callback);
|
||||
doSendMessage(numbers[i], devicesForNumber, message);
|
||||
}, function(error_msg) {
|
||||
errorThrown++;
|
||||
if (errorThrown == 1)
|
||||
error_callback("Failed to retreive new device keys for number " + numbers[i]);
|
||||
registerError(numbers[i], "Failed to retreive new device keys for number " + numbers[i]);
|
||||
});
|
||||
}
|
||||
} else
|
||||
doSendMessage(numbers[i], devicesForNumber, message);
|
||||
}
|
||||
if (deviceDatasMissing > 0 || errorThrown > 0) {
|
||||
loopDone = 1;
|
||||
return;
|
||||
}
|
||||
return sendMessageToDevices(deviceObjectList, message, function(result) {
|
||||
var successNumbers = {};
|
||||
var failureNumbers = {};
|
||||
for (var i = 0; i < result.success; i++)
|
||||
successNumbers[getNumberFromString(result.success[i])] = 1;
|
||||
for (var i = 0; i < result.failure; i++)
|
||||
failureNumbers[getNumberFromString(result.success[i])] = 1;
|
||||
|
||||
success_callback({success: successNumbers, failure: failureNumbers});
|
||||
}, error_callback);
|
||||
}
|
||||
|
||||
function requestIdentityPrivKeyFromMasterDevice(number, identityKey) {
|
||||
|
|
28
js/popup.js
28
js/popup.js
|
@ -41,10 +41,12 @@ registerOnLoadFunction(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
|
||||
|
||||
var messageProto = new PushMessageContentProtobuf();
|
||||
messageProto.body = $('#text' + i).val();
|
||||
|
||||
sendMessageToNumbers(sendDestinations, messageProto, function(result) {
|
||||
console.log("Sent message: " + result);
|
||||
});
|
||||
});
|
||||
ul.append('</li>');
|
||||
|
@ -59,5 +61,23 @@ registerOnLoadFunction(function() {
|
|||
fillMessages();
|
||||
storage.putUnencrypted("unreadCount", 0);
|
||||
chrome.browserAction.setBadgeText({text: ""});
|
||||
|
||||
$("#popup_send_button").click(function() {
|
||||
var numbers = [];
|
||||
var splitString = $("#popup_send_numbers").val().split(",");
|
||||
for (var i = 0; i < splitString.length; i++) {
|
||||
try {
|
||||
numbers.push(verifyNumber(splitString[i]));
|
||||
} catch (numberError) {
|
||||
//TODO
|
||||
alert(numberError);
|
||||
}
|
||||
}
|
||||
var messageProto = new PushMessageContentProtobuf();
|
||||
messageProto.body = $("#popup_send_message").val();
|
||||
sendMessageToNumbers(numbers, messageProto,
|
||||
//TODO: Handle result
|
||||
function(thing) {console.log(thing);});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
|
||||
<script type="text/javascript" src="js-deps/nacl-common.js"></script>
|
||||
<script type="text/javascript" src="js-deps/jquery.js"></script>
|
||||
<script type="text/javascript" src="js-deps/jquery.atmosphere.js"></script>
|
||||
<script type="text/javascript" src="js-deps/core.js"></script>
|
||||
<script type="text/javascript" src="js-deps/enc-base64.js"></script>
|
||||
<script type="text/javascript" src="js-deps/cipher-core.js"></script>
|
||||
|
|
10
popup.html
10
popup.html
|
@ -11,11 +11,16 @@
|
|||
<ul id="messages">
|
||||
</ul>
|
||||
</div>
|
||||
<div id="send" style="display:none;"></div>
|
||||
<div id="send" style="display:none;">
|
||||
<form>
|
||||
<input id="popup_send_numbers" />
|
||||
<input id="popup_send_text" />
|
||||
<a id="popup_send_button">Send</a>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="js-deps/nacl-common.js"></script>
|
||||
<script type="text/javascript" src="js-deps/jquery.js"></script>
|
||||
<script type="text/javascript" src="js-deps/jquery.atmosphere.js"></script>
|
||||
<script type="text/javascript" src="js-deps/core.js"></script>
|
||||
<script type="text/javascript" src="js-deps/enc-base64.js"></script>
|
||||
<script type="text/javascript" src="js-deps/cipher-core.js"></script>
|
||||
|
@ -30,7 +35,6 @@
|
|||
<script type="text/javascript" src="js-deps/ProtoBuf.min.js"></script>
|
||||
<script type="text/javascript" src="js/helpers.js"></script>
|
||||
<script type="text/javascript" src="js/api.js"></script>
|
||||
<script type="text/javascript" src="js/fake_api.js"></script>
|
||||
<script type="text/javascript" src="js/popup.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
<script type="text/javascript" src="js-deps/nacl-common.js"></script>
|
||||
<script type="text/javascript" src="js-deps/jquery.js"></script>
|
||||
<script type="text/javascript" src="js-deps/jquery.atmosphere.js"></script>
|
||||
<script type="text/javascript" src="js-deps/core.js"></script>
|
||||
<script type="text/javascript" src="js-deps/enc-base64.js"></script>
|
||||
<script type="text/javascript" src="js-deps/cipher-core.js"></script>
|
||||
|
@ -26,6 +25,9 @@
|
|||
<script type="text/javascript" src="js-deps/ByteBuffer.min.js"></script>
|
||||
<script type="text/javascript" src="js-deps/ProtoBuf.min.js"></script>
|
||||
<script type="text/javascript" src="js/helpers.js"></script>
|
||||
<!-- TODO: Tests for api stuff -->
|
||||
<script type="text/javascript" src="js/api.js"></script>
|
||||
<script type="text/javascript" src="js/fake_api.js"></script>
|
||||
<script type="text/javascript" src="js/test.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Reference in a new issue