From 753a95081604eb71671a544f85c3ea9e11186fb2 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Tue, 27 May 2014 20:40:39 +0200 Subject: [PATCH] Redo registration process --- js/api.js | 57 ++++++++++++++-------- js/helpers.js | 81 ++++++++++++++++++++---------- js/options.js | 133 ++++++++++++++++++++------------------------------ options.html | 2 +- 4 files changed, 145 insertions(+), 128 deletions(-) diff --git a/js/api.js b/js/api.js index 908e9a50..39d57c86 100644 --- a/js/api.js +++ b/js/api.js @@ -87,6 +87,28 @@ window.textsecure.api = function() { code = -1; var e = new Error(code); e.name = "HTTPError"; + switch (code) { + case -1: + e.human_error = "Failed to connect to the server, please check your network connection."; + break; + case 413: + e.human_error = "Rate limit exceeded, please try again later."; + break; + case 403: + e.human_error = "Invalid code, please try again."; + break; + case 417: + e.human_error = "Number already registered"; // TODO: This shouldn't be a thing?, but its in the API doc? + break; + case 401: + e.human_error = "Invalid authentication, most likely someone re-registered and invalidated our registration"; + break; + case 404: + e.human_error = "Number is not registered with TextSecure.."; + break; + default: + e.human_error = "The server rejected our query, please file a bug report."; + } reject(e); } }); @@ -108,28 +130,21 @@ window.textsecure.api = function() { }; self.confirmCode = function(code, number, password, - signaling_key, registrationId, single_device, - success_callback, error_callback) { - var call = single_device ? 'accounts' : 'devices'; - var urlPrefix = single_device ? '/code/' : '/'; + signaling_key, registrationId, single_device) { + var call = single_device ? 'accounts' : 'devices'; + var urlPrefix = single_device ? '/code/' : '/'; - doAjax({ - call : call, - httpType : 'PUT', - urlParameters : urlPrefix + code, - user : number, - password : password, - jsonData : { signalingKey : btoa(getString(signaling_key)), - supportsSms : false, - fetchesMessages : true, - registrationId : registrationId}, - }).then(function(response) { - if (success_callback !== undefined) - success_callback(response); - }).catch(function(code) { - if (error_callback !== undefined) - error_callback(code); - }); + return doAjax({ + call : call, + httpType : 'PUT', + urlParameters : urlPrefix + code, + user : number, + password : password, + jsonData : { signalingKey : btoa(getString(signaling_key)), + supportsSms : false, + fetchesMessages : true, + registrationId : registrationId}, + }); }; self.registerKeys = function(keys, success_callback, error_callback) { diff --git a/js/helpers.js b/js/helpers.js index 4e5381ab..45107990 100644 --- a/js/helpers.js +++ b/js/helpers.js @@ -207,45 +207,41 @@ window.textsecure.utils = function() { return [number.substr(1, 1), number.substr(2)]; //XXX } - function numberValid(number) { - return true; //XXX + function validateNumber(number, countryCode) { + return isNumeric(number) && number.length > 3 && number.length < 11; //XXX } - function countryCodeValid(number) { - return true; //XXX + function validateCountryCode(countryCode) { + return isNumeric(countryCode) && countryCode.length < 4 && countryCode.length > 0; } self.verifyNumber = function(number, countryCode) { + //XXX: All verifyNumber stuff needs to match the server-side verification var countryCodeValid = true; var numberValid = true; - if (countryCode !== undefined) { - var match = countryCode.match(/[0-9]{3}-?[0-9]{3}/g) - if (match == null || match.length == 1 || match[0] == countryCode) { - countryCodeValid = false; - countryCode = '1'; // Continue testing number with a fake countryCode - } - } - if (!isNumeric(number)) { - if (countryCode !== undefined || !number.startsWith('+') || !isNumeric(number.substr(1))) { - numberValid = false; - number = '2222222222'; // Continue testing countryCode with a fake number - } else { + if (number.substr(0, 1) == '+') { + if (countryCode === undefined) { var numberCCPair = splitPrefixedNumber(number); - countryCode = numberCCPair[0]; - number = numberCCPair[1]; - } - } - - if (numberValid && !verifyNumber(number)) + if (numberCCPair != null) { + countryCode = numberCCPair[0]; + number = numberCCPair[1]; + } else + numberValid = false; + } else + numberValid = false; + } else if (countryCode === undefined) numberValid = false; - if (countryCodeValid && !verifyCountryCode(countryCode)) - countryCodeValid = false; + + if (numberValid && !validateNumber(number, countryCode)) + numberValid = false; + if (countryCode !== undefined) + countryCodeValid = validateCountryCode(countryCode); if (!countryCodeValid || !numberValid) throw { countryCodeValid: countryCodeValid, numberValid: numberValid }; - return '+' + country_code + number; + return '+' + countryCode + number; } self.unencodeNumber = function(number) { @@ -615,6 +611,41 @@ window.textsecure.sendMessage = function() { } }(); +window.textsecure.register = function() { + return function(number, verificationCode, singleDevice, stepDone) { + var signalingKey = textsecure.crypto.getRandomBytes(32 + 20); + textsecure.storage.putEncrypted('signaling_key', signalingKey); + + var password = btoa(getString(textsecure.crypto.getRandomBytes(16))); + password = password.substring(0, password.length - 2); + textsecure.storage.putEncrypted("password", password); + + var registrationId = new Uint16Array(textsecure.crypto.getRandomBytes(2))[0]; + registrationId = registrationId & 0x3fff; + textsecure.storage.putUnencrypted("registrationId", registrationId); + + return textsecure.api.confirmCode(number, verificationCode, password, signalingKey, registrationId, singleDevice).then(function(response) { + if (singleDevice) + response = 1; + var numberId = number + "." + response; + textsecure.storage.putUnencrypted("number_id", numberId); + stepDone(1); + + if (!singleDevice) { + //TODO: Do things??? + stepDone(2); + } + + return textsecure.crypto.generateKeys().then(function(keys) { + stepDone(3); + return textsecure.api.registerKeys(keys).then(function() { + stepDone(4); + }); + }); + }); + } +}(); + function requestIdentityPrivKeyFromMasterDevice(number, identityKey) { //TODO } diff --git a/js/options.js b/js/options.js index 50832a8e..e0082f98 100644 --- a/js/options.js +++ b/js/options.js @@ -14,16 +14,16 @@ * along with this program. If not, see . */ -function updateCodeNumberColors() { +function updateNumberColors() { try { textsecure.utils.verifyNumber($('#number').val(), $('#countrycode').val()); $('#number').attr('style', ''); - $('#code').attr('style', ''); + $('#countrycode').attr('style', ''); } catch (e) { if (e.countryCodeValid) - $('#code').attr('style', ''); + $('#countrycode').attr('style', ''); else - $('#code').attr('style', 'background-color:#ff6666;'); + $('#countrycode').attr('style', 'background-color:#ff6666;'); if (e.numberValid) $('#number').attr('style', ''); @@ -32,15 +32,22 @@ function updateCodeNumberColors() { } } -$('#code').on('change', updateCodeNumberColors); -$('#number').on('change', updateCodeNumberColors); +$('#number').on('change', updateNumberColors); +$('#countrycode').on('change', updateNumberColors); + +function isCodeValid() { + var code = $('#code'); + return code.val().replace(/\D/g, '') == code.val() && code.val().length == 6; +} + +$('#code').on('change', function() { + if (!isCodeValid()) + $('#code').attr('style', 'background-color:#ff6666;'); + else + $('#code').attr('style', ''); +}); var single_device = false; -var signaling_key = textsecure.crypto.getRandomBytes(32 + 20); -var password = btoa(getString(textsecure.crypto.getRandomBytes(16))); -password = password.substring(0, password.length - 2); -var registrationId = new Uint16Array(textsecure.crypto.getRandomBytes(2))[0]; -registrationId = registrationId & 0x3fff; $('#init-go-single-client').click(function() { var number = textsecure.utils.verifyNumber($('#number').val(), $('#countrycode').val()); @@ -61,76 +68,40 @@ $('#init-go-single-client').click(function() { }); $('#init-go').click(function() { - if (codeMatches() && numberMatches()) { - var number = "+" + $('#countrycode').val().replace(/\D/g, '') + $('#number').val().replace(/\D/g, ''); - - $('#init-setup').hide(); - $('#verify1done').html(''); - $('#verify2').hide(); - $('#verify3done').html(''); - $('#verify4done').html(''); - $('#verify').show(); - - textsecure.api.confirmCode($('#code').val(), number, password, signaling_key, registrationId, single_device, - function(response) { - if (single_device) - response = 1; - var number_id = number + "." + response; - textsecure.storage.putEncrypted("password", password); - textsecure.storage.putEncrypted('signaling_key', signaling_key); - textsecure.storage.putUnencrypted("number_id", number_id); - textsecure.storage.putUnencrypted("registrationId", registrationId); - $('#verify1done').html('done'); - - var register_keys_func = function() { - $('#verify2done').html('done'); - textsecure.crypto.generateKeys().then(function(keys) { - $('#verify3done').html('done'); - textsecure.api.registerKeys(keys, - function(response) { - $('#complete-number').html(number); - $('#verify').hide(); - $('#setup-complete').show(); - registrationDone(); - }, function(code) { - alert(code); //TODO - } - ); - }); - } - - if (!single_device) { - //TODO: Redo all this - /*getKeysForNumber(number).then(function(identityKey) { - textsecure.subscribeToPush(function(message) { - //TODO receive shared identity key - register_keys_func(); - }); - requestIdentityPrivKeyFromMasterDevice(number); - }).catch(function(error) { - alert(error); //TODO - });*/ - register_keys_func(); - } else { - register_keys_func(); - } - }, function(code) { - var error; - switch(code) { - case 403: - error = "Invalid code, please try again."; - break; - case -1: - error = "Error connecting to server, please check your network connection."; - break; - default: - error = "Unknown error, please try again later."; - console.log("Got error code " + code); - } - alert(error); //TODO - } - ); + var number = textsecure.utils.verifyNumber($('#number').val(), $('#countrycode').val()); + if (!isCodeValid()) { + updateCodeColor(); + return; } + + + $('#init-setup').hide(); + $('#verify1done').html(''); + $('#verify2').hide(); + $('#verify3done').html(''); + $('#verify4done').html(''); + $('#verify').show(); + + textsecure.register($('#code').val(), number, single_device, function(step) { + switch(step) { + case 1: + $('#verify1done').html('done'); + break; + case 2: + $('#verify2done').html('done'); + break; + case 3: + $('#verify3done').html('done'); + break; + case 4: + $('#complete-number').html(number); + $('#verify').hide(); + $('#setup-complete').show(); + registrationDone(); + } + }).catch(function(error) { + alert(error.human_error); + }); }); textsecure.registerOnLoadFunction(function() { @@ -138,7 +109,7 @@ textsecure.registerOnLoadFunction(function() { if (!isRegistrationDone()) { $('#init-setup').show(); } else { - $('#complete-number').html(textsecure.storage.getUnencrypted("number_id").split(".")[0]); + $('#complete-number').html(textsecure.storage.getUnencrypted("number_id").split(".")[0]);//TODO: no $('#setup-complete').show(); } }); diff --git a/options.html b/options.html index 4c1e43bc..13d928ed 100644 --- a/options.html +++ b/options.html @@ -21,7 +21,7 @@
-

TextSecure

+

TextSecure