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>
|
<head>
|
||||||
<script type="text/javascript" src="js-deps/nacl-common.js"></script>
|
<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.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/core.js"></script>
|
||||||
<script type="text/javascript" src="js-deps/enc-base64.js"></script>
|
<script type="text/javascript" src="js-deps/enc-base64.js"></script>
|
||||||
<script type="text/javascript" src="js-deps/cipher-core.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-deps/ProtoBuf.min.js"></script>
|
||||||
<script type="text/javascript" src="js/helpers.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/api.js"></script>
|
||||||
<script type="text/javascript" src="js/fake_api.js"></script>
|
|
||||||
<script type="text/javascript" src="js/background.js"></script>
|
<script type="text/javascript" src="js/background.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body data-name="curve25519" data-tools="pnacl" data-configs="Debug Release" data-path="pnacl/{config}">
|
<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['accounts'] = "/v1/accounts";
|
||||||
URL_CALLS['devices'] = "/v1/devices";
|
URL_CALLS['devices'] = "/v1/devices";
|
||||||
URL_CALLS['keys'] = "/v1/keys";
|
URL_CALLS['keys'] = "/v1/keys";
|
||||||
URL_CALLS['push'] = "/v1/messagesocket";
|
URL_CALLS['push'] = "/v1/websocket";
|
||||||
URL_CALLS['messages'] = "/v1/messages/";
|
URL_CALLS['messages'] = "/v1/messages";
|
||||||
|
|
||||||
var API = new function() {
|
var API = new function() {
|
||||||
|
|
||||||
|
@ -119,16 +119,34 @@ var API = new function() {
|
||||||
call : 'keys',
|
call : 'keys',
|
||||||
httpType : 'GET',
|
httpType : 'GET',
|
||||||
do_auth : true,
|
do_auth : true,
|
||||||
urlParameters : "/" + getNumberFromString(number) + "?multikeys",
|
urlParameters : "/" + getNumberFromString(number) + "/*",
|
||||||
success_callback : success_callback,
|
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
|
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({
|
this.doAjax({
|
||||||
call : 'messages',
|
call : 'messages',
|
||||||
httpType : 'POST',
|
httpType : 'PUT',
|
||||||
|
urlParameters : '/' + destination,
|
||||||
do_auth : true,
|
do_auth : true,
|
||||||
jsonData : jsonData,
|
jsonData : jsonData,
|
||||||
success_callback : success_callback,
|
success_callback : success_callback,
|
||||||
|
|
228
js/helpers.js
228
js/helpers.js
|
@ -206,6 +206,11 @@ function getEncodedNumber(number) {
|
||||||
return number;
|
return number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function verifyNumber(string) {
|
||||||
|
//TODO: fancy country-code guessing and number verification
|
||||||
|
return getEncodedNumber(string.trim());
|
||||||
|
}
|
||||||
|
|
||||||
function getDeviceId(encodedNumber) {
|
function getDeviceId(encodedNumber) {
|
||||||
var split = encodedNumber.split(".");
|
var split = encodedNumber.split(".");
|
||||||
if (split.length > 1)
|
if (split.length > 1)
|
||||||
|
@ -865,51 +870,51 @@ var crypto_tests = {};
|
||||||
function subscribeToPush(message_callback) {
|
function subscribeToPush(message_callback) {
|
||||||
var user = storage.getUnencrypted("number_id");
|
var user = storage.getUnencrypted("number_id");
|
||||||
var password = storage.getEncrypted("password");
|
var password = storage.getEncrypted("password");
|
||||||
var request = { url: URL_BASE + URL_CALLS['push'] + "/?user=%2B" + getString(user).substring(1) + "&password=" + getString(password),
|
var URL = URL_BASE.replace(/^http:/g, "ws:").replace(/^https:/g, "wss:") + URL_CALLS['push'] + "/?user=%2B" + getString(user).substring(1) + "&password=" + getString(password);
|
||||||
method: 'GET',
|
var socket = new WebSocket(URL);
|
||||||
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 proto;
|
//TODO: GUI
|
||||||
try {
|
socket.onerror = function(socketEvent) {
|
||||||
var plaintext = crypto.decryptWebsocketMessage(message.message);
|
console.log('Server is down :(');
|
||||||
var proto = decodeIncomingPushMessageProtobuf(plaintext);
|
setTimeout(function() { subscribeToPush(message_callback); }, 1000);
|
||||||
// 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
|
socket.onclose = function(socketEvent) {
|
||||||
API.pushMessage(message.id);
|
console.log('Server closed :(');
|
||||||
} catch (e) {
|
setTimeout(function() { subscribeToPush(message_callback); }, 1000);
|
||||||
console.log("Error decoding message: " + e);
|
};
|
||||||
return;
|
socket.onopen = function(socketEvent) {
|
||||||
}
|
console.log('Connected to server!');
|
||||||
|
};
|
||||||
|
|
||||||
try {
|
socket.onmessage = function(response) {
|
||||||
crypto.handleIncomingPushMessageProto(proto, function(decrypted) {
|
try {
|
||||||
message_callback(decrypted);
|
// Some bug in Atmosphere.js is forcing trackMessageLength to true
|
||||||
}); // Decrypts/decodes/fills in fields/etc
|
var message = JSON.parse(response.responseBody.split("|")[1]);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
//TODO: Tell the user decryption failed
|
console.log('Error parsing server JSON message: ' + response.responseBody.split("|")[1]);
|
||||||
}
|
return;
|
||||||
},
|
}
|
||||||
onError: function(response) {
|
|
||||||
console.log('Server is down :(');
|
var proto;
|
||||||
//TODO: GUI
|
try {
|
||||||
}};
|
var plaintext = crypto.decryptWebsocketMessage(message.message);
|
||||||
$.atmosphere.subscribe(request);
|
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)
|
// 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)
|
// success_callback(server success/failure map), error_callback(error_msg)
|
||||||
// message == PushMessageContentProto (NOT STRING)
|
// message == PushMessageContentProto (NOT STRING)
|
||||||
function sendMessageToDevices(deviceObjectList, message, success_callback, error_callback) {
|
function sendMessageToDevices(number, deviceObjectList, message, success_callback, error_callback) {
|
||||||
var jsonData = [];
|
var jsonData = [];
|
||||||
for (var i = 0; i < deviceObjectList.legnth; i++) {
|
var relay = undefined;
|
||||||
var encryptedMsg = encryptMessageFor(deviceObjectList[i], message);
|
|
||||||
jsonData[jsonData.length] = {
|
var doSend = function() {
|
||||||
type: encryptedMsg.type,
|
API.sendMessages(number, jsonData,
|
||||||
destination: deviceObjectList[i].encodedNumber,
|
function(result) {
|
||||||
body: encryptedMsg.body,
|
success_callback(result);
|
||||||
relay: deviceObjectList[i].relay,
|
}, function(code) {
|
||||||
timestamp: new Date().getTime()
|
error_callback(code);
|
||||||
};
|
}
|
||||||
//TODO: need to encrypt with session key?
|
);
|
||||||
}
|
}
|
||||||
API.sendMessages(jsonData,
|
|
||||||
function(result) {
|
var addEncryptionFor;
|
||||||
if (result.missingDeviceIds.length > 0) {
|
addEncryptionFor = function(i) {
|
||||||
var responsesLeft = result.missingDeviceIds.length;
|
crypto.encryptMessageFor(deviceObjectList[i], message, function(encryptedMsg) {
|
||||||
var errorThrown = 0;
|
jsonData[i] = {
|
||||||
for (var i = 0; i < result.missingDeviceIds.length; i++) {
|
type: encryptedMsg.type,
|
||||||
getKeysForNumber(result.missingDeviceIds[i], function(identity_key) {
|
destination: deviceObjectList[i].encodedNumber,
|
||||||
responsesLeft--;
|
body: encryptedMsg.body,
|
||||||
if (responsesLeft == 0 && errorThrown == 0)
|
timestamp: new Date().getTime()
|
||||||
sendMessageToDevices(deviceObjectList, message, success_callback, error_callback);
|
};
|
||||||
}, function(error_msg) {
|
|
||||||
errorThrown++;
|
if (deviceObjectList[i].relay !== undefined) {
|
||||||
if (errorThrown == 1)
|
jsonData[i].relay = deviceObjectList[i].relay;
|
||||||
error_callback("Failed to retreive new device keys for number " + result.missingDeviceIds[i]);
|
if (relay === undefined)
|
||||||
});
|
relay = jsonData[i].relay;
|
||||||
|
else if (relay != jsonData[i].relay) {
|
||||||
|
error_callback("Mismatched relays for number " + number);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} 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)
|
// callback(success/failure map, see code)
|
||||||
function sendMessageToNumbers(numbers, message, success_callback, error_callback) {
|
// message == PushMessageContentProto (NOT STRING)
|
||||||
var deviceObjectList = [];
|
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++) {
|
for (var i = 0; i < numbers.length; i++) {
|
||||||
var devicesForNumber = getDeviceObjectListFromNumber(numbers[i]);
|
var devicesForNumber = getDeviceObjectListFromNumber(numbers[i]);
|
||||||
for (var j = 0; j < devicesForNumber.length; j++)
|
|
||||||
deviceObjectList[deviceObjectList.length] = devicesForNumber[j];
|
|
||||||
|
|
||||||
if (devicesForNumber.length == 0) {
|
if (devicesForNumber.length == 0) {
|
||||||
deviceDatasMissing++;
|
|
||||||
getKeysForNumber(numbers[i], function(identity_key) {
|
getKeysForNumber(numbers[i], function(identity_key) {
|
||||||
deviceDatasMissing--;
|
doSendMessage(numbers[i], devicesForNumber, message);
|
||||||
if (deviceDatasMissing == 0 && loopDone && errorThrown == 0)
|
|
||||||
sendMessageToNumbers(numbers, message, success_callback, error_callback);
|
|
||||||
}, function(error_msg) {
|
}, function(error_msg) {
|
||||||
errorThrown++;
|
registerError(numbers[i], "Failed to retreive new device keys for number " + numbers[i]);
|
||||||
if (errorThrown == 1)
|
|
||||||
error_callback("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) {
|
function requestIdentityPrivKeyFromMasterDevice(number, identityKey) {
|
||||||
|
|
28
js/popup.js
28
js/popup.js
|
@ -41,10 +41,12 @@ registerOnLoadFunction(function() {
|
||||||
var sendDestinations = [conversation[0].sender];
|
var sendDestinations = [conversation[0].sender];
|
||||||
for (var j = 0; j < conversation[0].destinations.length; j++)
|
for (var j = 0; j < conversation[0].destinations.length; j++)
|
||||||
sendDestinations[sendDestinations.length] = conversation[0].destinations[j];
|
sendDestinations[sendDestinations.length] = conversation[0].destinations[j];
|
||||||
sendMessageToNumbers(sendDestinations, { message: $('#text' + i).val() }, function(result) {
|
|
||||||
console.log("Sent message: " + JSON.stringify(result));
|
var messageProto = new PushMessageContentProtobuf();
|
||||||
}, function(error_msg) {
|
messageProto.body = $('#text' + i).val();
|
||||||
alert(error_msg); //TODO
|
|
||||||
|
sendMessageToNumbers(sendDestinations, messageProto, function(result) {
|
||||||
|
console.log("Sent message: " + result);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
ul.append('</li>');
|
ul.append('</li>');
|
||||||
|
@ -59,5 +61,23 @@ registerOnLoadFunction(function() {
|
||||||
fillMessages();
|
fillMessages();
|
||||||
storage.putUnencrypted("unreadCount", 0);
|
storage.putUnencrypted("unreadCount", 0);
|
||||||
chrome.browserAction.setBadgeText({text: ""});
|
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/nacl-common.js"></script>
|
||||||
<script type="text/javascript" src="js-deps/jquery.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/core.js"></script>
|
||||||
<script type="text/javascript" src="js-deps/enc-base64.js"></script>
|
<script type="text/javascript" src="js-deps/enc-base64.js"></script>
|
||||||
<script type="text/javascript" src="js-deps/cipher-core.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 id="messages">
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</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/nacl-common.js"></script>
|
||||||
<script type="text/javascript" src="js-deps/jquery.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/core.js"></script>
|
||||||
<script type="text/javascript" src="js-deps/enc-base64.js"></script>
|
<script type="text/javascript" src="js-deps/enc-base64.js"></script>
|
||||||
<script type="text/javascript" src="js-deps/cipher-core.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-deps/ProtoBuf.min.js"></script>
|
||||||
<script type="text/javascript" src="js/helpers.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/api.js"></script>
|
||||||
<script type="text/javascript" src="js/fake_api.js"></script>
|
|
||||||
<script type="text/javascript" src="js/popup.js"></script>
|
<script type="text/javascript" src="js/popup.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
|
|
||||||
<script type="text/javascript" src="js-deps/nacl-common.js"></script>
|
<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.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/core.js"></script>
|
||||||
<script type="text/javascript" src="js-deps/enc-base64.js"></script>
|
<script type="text/javascript" src="js-deps/enc-base64.js"></script>
|
||||||
<script type="text/javascript" src="js-deps/cipher-core.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/ByteBuffer.min.js"></script>
|
||||||
<script type="text/javascript" src="js-deps/ProtoBuf.min.js"></script>
|
<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/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>
|
<script type="text/javascript" src="js/test.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Add table
Reference in a new issue