diff --git a/background.html b/background.html index 548a7b27..d4a7773a 100644 --- a/background.html +++ b/background.html @@ -16,6 +16,8 @@ + + diff --git a/js/api.js b/js/api.js new file mode 100644 index 00000000..dae8ecd4 --- /dev/null +++ b/js/api.js @@ -0,0 +1,145 @@ +/************************************************ + *** Utilities to communicate with the server *** + ************************************************/ +var URL_BASE = "http://textsecure-test.herokuapp.com"; +//var URL_BASE = "https://textsecure-service.whispersystems.org"; +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/"; + +var API = new function() { + + /** + * REQUIRED PARAMS: + * call: URL_CALLS entry + * httpType: POST/GET/PUT/etc + * OPTIONAL PARAMS: + * success_callback: function(response object) called on success + * error_callback: function(http status code = -1 or != 200) called on failure + * urlParameters: crap appended to the url (probably including a leading /) + * user: user name to be sent in a basic auth header + * password: password to be sent in a basic auth headerA + * do_auth: alternative to user/password where user/password are figured out automagically + * jsonData: JSON data sent in the request body + */ + this.doAjax = function doAjax(param) { + if (param.urlParameters === undefined) + param.urlParameters = ""; + + if (param.do_auth) { + param.user = storage.getUnencrypted("number_id"); + param.password = storage.getEncrypted("password"); + } + + $.ajax(URL_BASE + URL_CALLS[param.call] + param.urlParameters, { + type : param.httpType, + data : param.jsonData && jsonThing(param.jsonData), + contentType : 'application/json; charset=utf-8', + dataType : 'json', + + beforeSend : function(xhr) { + if (param.user !== undefined && + param.password !== undefined) { + xhr.setRequestHeader("Authorization", "Basic " + btoa(getString(param.user) + ":" + getString(param.password))); + } + }, + + success : function(response, textStatus, jqXHR) { + if (param.success_callback !== undefined) + param.success_callback(response); + }, + + error : function(jqXHR, textStatus, errorThrown) { + var code = jqXHR.status; + if (code == 200) { + // happens sometimes when we get no response + // (TODO: Fix server to return 204? instead) + if (param.success_callback !== undefined) + param.success_callback(null); + return; + } + if (code > 999 || code < 100) + code = -1; + if (param.error_callback !== undefined) + param.error_callback(code); + } + }); + }; + + + this.requestVerificationCode = function(number, success_callback, error_callback) { + this.doAjax({ + call : 'accounts', + httpType : 'GET', + urlParameters : '/sms/code/' + number, + success_callback : success_callback, + error_callback : error_callback + }); + }; + + this.confirmCode = function(code, number, password, + signaling_key, single_device, + success_callback, error_callback) { + var call = single_device ? 'accounts' : 'devices'; + var urlPrefix = single_device ? '/code/' : '/'; + + API.doAjax({ + call : call, + httpType : 'PUT', + urlParameters : urlPrefix + code, + user : number, + password : password, + jsonData : { signalingKey : btoa(getString(signaling_key)), + supportsSms : false, + fetchesMessages : true }, + success_callback : success_callback, + error_callback : error_callback + }); + }; + + this.registerKeys = function(keys, success_callback, error_callback) { + this.doAjax({ + call : 'keys', + httpType : 'PUT', + do_auth : true, + jsonData : keys, + success_callback : success_callback, + error_callback : error_callback + }); + }; + + this.getKeysForNumber = function(number, success_callback, error_callback) { + this.doAjax({ + call : 'keys', + httpType : 'GET', + do_auth : true, + urlParameters : "/" + getNumberFromString(number) + "?multikeys", + success_callback : success_callback, + error_callback : error_callback + }); + }; + + this.sendMessages = function(jsonData, success_callback, error_callback) { + this.doAjax({ + call : 'messages', + httpType : 'POST', + do_auth : true, + jsonData : jsonData, + success_callback : success_callback, + error_callback : error_callback + }); + }; + + this.pushMessage = function(messageId) { + this.doAjax({ + call : 'push', + httpType : 'PUT', + urlParameters : '/' + message.id, + do_auth : true + }); + }; + +}(); // API diff --git a/js/fake_api.js b/js/fake_api.js new file mode 100644 index 00000000..8d1e099a --- /dev/null +++ b/js/fake_api.js @@ -0,0 +1,27 @@ +var FakeWhisperAPI = function() { + + this.doAjax = function(param) { + if (param.success_callback) { + setTimeout(param.success_callback, 100, param.response); + } + } + + this.getKeysForNumber = function(number, success_callback, error_callback) { + this.doAjax({ success_callback: success_callback, + response : [{ identityKey: 1, + deviceId : 1, + publicKey : 1, + keyId : 1 }] + }); + } + + this.sendMessages = function(jsonData, success_callback, error_callback) { + this.doAjax({ success_callback: success_callback, + response : { missingDeviceIds: [] } + }); + } +}; + +FakeWhisperAPI.prototype = API; +API = new FakeWhisperAPI(); + diff --git a/js/helpers.js b/js/helpers.js index 432b4612..85125d66 100644 --- a/js/helpers.js +++ b/js/helpers.js @@ -139,7 +139,7 @@ function ensureStringed(thing) { else if (thing instanceof Array) { var res = []; for (var i = 0; i < thing.length; i++) - res[i] = ensureStringed(thing); + res[i] = ensureStringed(thing[i]); return res; } else if (thing === Object(thing)) { var res = {}; @@ -860,65 +860,6 @@ var crypto_tests = {}; }( window.crypto = window.crypto || {}, jQuery )); -/************************************************ - *** Utilities to communicate with the server *** - ************************************************/ -var URL_BASE = "http://textsecure-test.herokuapp.com"; -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/"; - -/** - * REQUIRED PARAMS: - * call: URL_CALLS entry - * httpType: POST/GET/PUT/etc - * OPTIONAL PARAMS: - * success_callback: function(response object) called on success - * error_callback: function(http status code = -1 or != 200) called on failure - * urlParameters: crap appended to the url (probably including a leading /) - * user: user name to be sent in a basic auth header - * password: password to be sent in a basic auth headerA - * do_auth: alternative to user/password where user/password are figured out automagically - * jsonData: JSON data sent in the request body - */ -function doAjax(param) { - if (param.urlParameters === undefined) - param.urlParameters = ""; - if (param.do_auth) { - param.user = storage.getUnencrypted("number_id"); - param.password = storage.getEncrypted("password"); - } - $.ajax(URL_BASE + URL_CALLS[param.call] + param.urlParameters, { - type: param.httpType, - data: param.jsonData && jsonThing(param.jsonData), - contentType: 'application/json; charset=utf-8', - dataType: 'json', - beforeSend: function(xhr) { - if (param.user !== undefined && param.password !== undefined) - xhr.setRequestHeader("Authorization", "Basic " + btoa(getString(param.user) + ":" + getString(param.password))); - }, - success: function(response, textStatus, jqXHR) { - if (param.success_callback !== undefined) - param.success_callback(response); - }, - error: function(jqXHR, textStatus, errorThrown) { - var code = jqXHR.status; - if (code == 200) {// happens sometimes when we get no response (TODO: Fix server to return 204? instead) - if (param.success_callback !== undefined) - param.success_callback(null); - return; - } - if (code > 999 || code < 100) - code = -1; - if (param.error_callback !== undefined) - param.error_callback(code); - }, - cache: false - }); -} // message_callback(decoded_protobuf) (use decodeMessage(proto)) function subscribeToPush(message_callback) { @@ -951,7 +892,7 @@ function subscribeToPush(message_callback) { // 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 - doAjax({call: 'push', httpType: 'PUT', urlParameters: '/' + message.id, do_auth: true}); + API.pushMessage(message.id); } catch (e) { console.log("Error decoding message: " + e); return; @@ -974,8 +915,8 @@ function subscribeToPush(message_callback) { // success_callback(identity_key), error_callback(error_msg) function getKeysForNumber(number, success_callback, error_callback) { - doAjax({call: 'keys', httpType: 'GET', do_auth: true, urlParameters: "/" + getNumberFromString(number) + "?multikeys", - success_callback: function(response) { + API.getKeysForNumber(number, + function(response) { for (var i = 0; i < response.length; i++) { try { saveDeviceObject({ @@ -990,10 +931,9 @@ function getKeysForNumber(number, success_callback, error_callback) { } } success_callback(response[0].identityKey); - }, error_callback: function(code) { + }, function(code) { error_callback("Error making HTTP request: " + code); - } - }); + }); } // success_callback(server success/failure map), error_callback(error_msg) @@ -1011,8 +951,8 @@ function sendMessageToDevices(deviceObjectList, message, success_callback, error }; //TODO: need to encrypt with session key? } - doAjax({call: 'messages', httpType: 'POST', do_auth: true, jsonData: jsonData, - success_callback: function(result) { + API.sendMessages(jsonData, + function(result) { if (result.missingDeviceIds.length > 0) { var responsesLeft = result.missingDeviceIds.length; var errorThrown = 0; @@ -1030,10 +970,10 @@ function sendMessageToDevices(deviceObjectList, message, success_callback, error } else { success_callback(result); } - }, error_callback: function(code) { + }, function(code) { error_callback("Failed to conect to data channel: " + code); } - }); + ); } // success_callback(success/failure map, see second-to-last line), error_callback(error_msg) diff --git a/js/options.js b/js/options.js index 5f4bb587..615f6e66 100644 --- a/js/options.js +++ b/js/options.js @@ -38,12 +38,12 @@ $('#init-go-single-client').click(function() { single_device = true; - doAjax({call: 'accounts', httpType: 'GET', urlParameters: '/sms/code/' + number, - success_callback: function(response) { }, - error_callback: function(code) { + API.requestVerificationCode(number, + function(response) { }, + function(code) { alert("Failed to send key?" + code); //TODO } - }); + ); } }); @@ -58,12 +58,8 @@ $('#init-go').click(function() { $('#verify4done').html(''); $('#verify').show(); - var call = single_device ? 'accounts' : 'devices'; - var urlPrefix = single_device ? '/code/' : '/'; - - doAjax({call: call, httpType: 'PUT', urlParameters: urlPrefix + $('#code').val(), user: number, password: password, - jsonData: {signalingKey: btoa(getString(signaling_key)), supportsSms: false, fetchesMessages: true}, - success_callback: function(response) { + API.confirmCode(code, number, password, signaling_key, single_device, + function(response) { if (single_device) response = 1; var number_id = number + "." + response; @@ -76,16 +72,16 @@ $('#init-go').click(function() { $('#verify2done').html('done'); crypto.generateKeys(function(keys) { $('#verify3done').html('done'); - doAjax({call: 'keys', httpType: 'PUT', do_auth: true, jsonData: keys, - success_callback: function(response) { + API.registerKeys(keys, + function(response) { $('#complete-number').html(number); $('#verify').hide(); $('#setup-complete').show(); registrationDone(); - }, error_callback: function(code) { + }, function(code) { alert(code); //TODO } - }); + ); }); } @@ -102,7 +98,7 @@ $('#init-go').click(function() { } else { register_keys_func(); } - }, error_callback: function(code) { + }, function(code) { var error; switch(code) { case 403: @@ -117,7 +113,7 @@ $('#init-go').click(function() { } alert(error); //TODO } - }); + ); } }); diff --git a/options.html b/options.html index 4aa16b6e..b5d34b2d 100644 --- a/options.html +++ b/options.html @@ -40,6 +40,8 @@ + + diff --git a/popup.html b/popup.html index 49408cef..da4b9b72 100644 --- a/popup.html +++ b/popup.html @@ -29,6 +29,8 @@ + +