improved number validation (based on google's libphonenumber)
This commit is contained in:
parent
92514ad08f
commit
13a9329bcf
10 changed files with 577 additions and 82 deletions
|
@ -198,57 +198,47 @@ window.textsecure.utils = function() {
|
|||
/****************************************
|
||||
*** Number conversion/checking stuff ***
|
||||
****************************************/
|
||||
function isNumeric(string) {
|
||||
return string.replace(/\D/g, '') === string;
|
||||
}
|
||||
self.getAllRegionCodes = function() {
|
||||
return {"AD":"Andorra","AE":"United Arab Emirates","AF":"Afghanistan","AG":"Antigua and Barbuda","AI":"Anguilla","AL":"Albania","AM":"Armenia","AO":"Angola","AR":"Argentina","AS":"AmericanSamoa","AT":"Austria","AU":"Australia","AW":"Aruba","AX":"Åland Islands","AZ":"Azerbaijan","BA":"Bosnia and Herzegovina","BB":"Barbados","BD":"Bangladesh","BE":"Belgium","BF":"Burkina Faso","BG":"Bulgaria","BH":"Bahrain","BI":"Burundi","BJ":"Benin","BL":"Saint Barthélemy","BM":"Bermuda","BN":"Brunei Darussalam","BO":"Bolivia, Plurinational State of","BR":"Brazil","BS":"Bahamas","BT":"Bhutan","BW":"Botswana","BY":"Belarus","BZ":"Belize","CA":"Canada","CC":"Cocos (Keeling) Islands","CD":"Congo, The Democratic Republic of the","CF":"Central African Republic","CG":"Congo","CH":"Switzerland","CI":"Cote d'Ivoire","CK":"Cook Islands","CL":"Chile","CM":"Cameroon","CN":"China","CO":"Colombia","CR":"Costa Rica","CU":"Cuba","CV":"Cape Verde","CX":"Christmas Island","CY":"Cyprus","CZ":"Czech Republic","DE":"Germany","DJ":"Djibouti","DK":"Denmark","DM":"Dominica","DO":"Dominican Republic","DZ":"Algeria","EC":"Ecuador","EE":"Estonia","EG":"Egypt","ER":"Eritrea","ES":"Spain","ET":"Ethiopia","FI":"Finland","FJ":"Fiji","FK":"Falkland Islands (Malvinas)","FM":"Micronesia, Federated States of","FO":"Faroe Islands","FR":"France","GA":"Gabon","GB":"United Kingdom","GD":"Grenada","GE":"Georgia","GF":"French Guiana","GG":"Guernsey","GH":"Ghana","GI":"Gibraltar","GL":"Greenland","GM":"Gambia","GN":"Guinea","GP":"Guadeloupe","GQ":"Equatorial Guinea","GR":"Ελλάδα","GT":"Guatemala","GU":"Guam","GW":"Guinea-Bissau","GY":"Guyana","HK":"Hong Kong","HN":"Honduras","HR":"Croatia","HT":"Haiti","HU":"Magyarország","ID":"Indonesia","IE":"Ireland","IL":"Israel","IM":"Isle of Man","IN":"India","IO":"British Indian Ocean Territory","IQ":"Iraq","IR":"Iran, Islamic Republic of","IS":"Iceland","IT":"Italy","JE":"Jersey","JM":"Jamaica","JO":"Jordan","JP":"Japan","KE":"Kenya","KG":"Kyrgyzstan","KH":"Cambodia","KI":"Kiribati","KM":"Comoros","KN":"Saint Kitts and Nevis","KP":"Korea, Democratic People's Republic of","KR":"Korea, Republic of","KW":"Kuwait","KY":"Cayman Islands","KZ":"Kazakhstan","LA":"Lao People's Democratic Republic","LB":"Lebanon","LC":"Saint Lucia","LI":"Liechtenstein","LK":"Sri Lanka","LR":"Liberia","LS":"Lesotho","LT":"Lithuania","LU":"Luxembourg","LV":"Latvia","LY":"Libyan Arab Jamahiriya","MA":"Morocco","MC":"Monaco","MD":"Moldova, Republic of","ME":"Црна Гора","MF":"Saint Martin","MG":"Madagascar","MH":"Marshall Islands","MK":"Macedonia, The Former Yugoslav Republic of","ML":"Mali","MM":"Myanmar","MN":"Mongolia","MO":"Macao","MP":"Northern Mariana Islands","MQ":"Martinique","MR":"Mauritania","MS":"Montserrat","MT":"Malta","MU":"Mauritius","MV":"Maldives","MW":"Malawi","MX":"Mexico","MY":"Malaysia","MZ":"Mozambique","NA":"Namibia","NC":"New Caledonia","NE":"Niger","NF":"Norfolk Island","NG":"Nigeria","NI":"Nicaragua","NL":"Netherlands","NO":"Norway","NP":"Nepal","NR":"Nauru","NU":"Niue","NZ":"New Zealand","OM":"Oman","PA":"Panama","PE":"Peru","PF":"French Polynesia","PG":"Papua New Guinea","PH":"Philippines","PK":"Pakistan","PL":"Polska","PM":"Saint Pierre and Miquelon","PR":"Puerto Rico","PS":"Palestinian Territory, Occupied","PT":"Portugal","PW":"Palau","PY":"Paraguay","QA":"Qatar","RE":"Réunion","RO":"Romania","RS":"Србија","RU":"Russia","RW":"Rwanda","SA":"Saudi Arabia","SB":"Solomon Islands","SC":"Seychelles","SD":"Sudan","SE":"Sweden","SG":"Singapore","SH":"Saint Helena, Ascension and Tristan Da Cunha","SI":"Slovenia","SJ":"Svalbard and Jan Mayen","SK":"Slovakia","SL":"Sierra Leone","SM":"San Marino","SN":"Senegal","SO":"Somalia","SR":"Suriname","ST":"Sao Tome and Principe","SV":"El Salvador","SY":"Syrian Arab Republic","SZ":"Swaziland","TC":"Turks and Caicos Islands","TD":"Chad","TG":"Togo","TH":"Thailand","TJ":"Tajikistan","TK":"Tokelau","TL":"Timor-Leste","TM":"Turkmenistan","TN":"Tunisia","TO":"Tonga","TR":"Turkey","TT":"Trinidad and Tobago","TV":"Tuvalu","TW":"Taiwan, Province of China","TZ":"Tanzania, United Republic of","UA":"Ukraine","UG":"Uganda","US":"United States","UY":"Uruguay","UZ":"Uzbekistan","VA":"Holy See (Vatican City State)","VC":"Saint Vincent and the Grenadines","VE":"Venezuela","VG":"Virgin Islands, British","VI":"Virgin Islands, U.S.","VN":"Viet Nam","VU":"Vanuatu","WF":"Wallis and Futuna","WS":"Samoa","YE":"Yemen","YT":"Mayotte","ZA":"South Africa","ZM":"Zambia","ZW":"Zimbabwe"};
|
||||
};
|
||||
|
||||
function splitPrefixedNumber(number) {
|
||||
// number == "+CCNumber"
|
||||
return [number.substr(1, 1), number.substr(2)]; //XXX
|
||||
}
|
||||
self.getRegionCodeForCountryCode = function(countryCode) {
|
||||
return libphonenumber.getRegionCodeForCountryCode(countryCode);
|
||||
};
|
||||
|
||||
function validateNumber(number, countryCode) {
|
||||
return isNumeric(number) && number.length > 3 && number.length < 11; //XXX
|
||||
}
|
||||
self.getRegionCodeForNumber = function(number) {
|
||||
try {
|
||||
var parsedNumber = libphonenumber.parse(number);
|
||||
return libphonenumber.getRegionCodeForNumber(parsedNumber);
|
||||
} catch(e) {
|
||||
return "ZZ";
|
||||
}
|
||||
};
|
||||
|
||||
function validateCountryCode(countryCode) {
|
||||
return isNumeric(countryCode) && countryCode.length < 4 && countryCode.length > 0;
|
||||
}
|
||||
self.getCountryCodeForRegion = function(regionCode) {
|
||||
var cc = libphonenumber.getCountryCodeForRegion(regionCode);
|
||||
return (cc != 0) ? cc : "";
|
||||
};
|
||||
|
||||
// Verifies a number (possibly tweaking its format)
|
||||
// This should be used ONLY to verify numbers provided by the user
|
||||
self.verifyNumber = function(number, countryCode) {
|
||||
//XXX: All verifyNumber stuff needs to match the server-side verification
|
||||
var countryCodeValid = true;
|
||||
var numberValid = true;
|
||||
self.verifyNumber = function(number, regionCode) {
|
||||
var parsedNumber = libphonenumber.parse(number, regionCode);
|
||||
|
||||
if (number.substr(0, 1) == '+') {
|
||||
if (countryCode === undefined) {
|
||||
var numberCCPair = splitPrefixedNumber(number);
|
||||
if (numberCCPair != null) {
|
||||
countryCode = numberCCPair[0];
|
||||
number = numberCCPair[1];
|
||||
} else
|
||||
numberValid = false;
|
||||
} else
|
||||
numberValid = false;
|
||||
} else if (countryCode === undefined)
|
||||
numberValid = false;
|
||||
if(!regionCode || regionCode == 'ZZ')
|
||||
regionCode = libphonenumber.getRegionCodeForNumber(parsedNumber);
|
||||
|
||||
if (numberValid && !validateNumber(number, countryCode))
|
||||
numberValid = false;
|
||||
if (countryCode !== undefined)
|
||||
countryCodeValid = validateCountryCode(countryCode);
|
||||
var isValidNumber = libphonenumber.isValidNumber(parsedNumber);
|
||||
var isValidNumberForRegion = libphonenumber.isValidNumberForRegion(parsedNumber, regionCode);
|
||||
|
||||
if (!countryCodeValid || !numberValid)
|
||||
throw { countryCodeValid: countryCodeValid, numberValid: numberValid };
|
||||
|
||||
return '+' + countryCode + number;
|
||||
}
|
||||
if (isValidNumber && isValidNumberForRegion) {
|
||||
return libphonenumber.format(parsedNumber, libphonenumber.PhoneNumberFormat.E164);
|
||||
} else {
|
||||
throw new Error("The number seems not to be valid.");
|
||||
}
|
||||
};
|
||||
|
||||
self.unencodeNumber = function(number) {
|
||||
return number.split(".");
|
||||
}
|
||||
};
|
||||
|
||||
/**************************
|
||||
*** JSON'ing Utilities ***
|
||||
|
@ -770,6 +760,7 @@ window.textsecure.register = function() {
|
|||
response = 1;
|
||||
var numberId = number + "." + response;
|
||||
textsecure.storage.putUnencrypted("number_id", numberId);
|
||||
textsecure.storage.putUnencrypted("regionCode", textsecure.utils.getRegionCodeForNumber(number));
|
||||
stepDone(1);
|
||||
|
||||
if (!singleDevice) {
|
||||
|
|
|
@ -16,25 +16,17 @@
|
|||
|
||||
function updateNumberColors() {
|
||||
try {
|
||||
textsecure.utils.verifyNumber($('#number').val(), $('#countrycode').val());
|
||||
if($('#number').val() != "" && $('#regionCode').val() != "")
|
||||
textsecure.utils.verifyNumber($('#number').val(), $('#regionCode').val());
|
||||
$('#countrycode').removeClass('invalid');
|
||||
$('#number').removeClass('invalid');
|
||||
$('#number').removeClass('invalid');
|
||||
} catch (e) {
|
||||
if (e.countryCodeValid)
|
||||
$('#countrycode').removeClass('invalid');
|
||||
else
|
||||
$('#countrycode').addClass('invalid');
|
||||
|
||||
if (e.numberValid)
|
||||
$('#number').removeClass('invalid');
|
||||
else
|
||||
$('#number').addClass('invalid');
|
||||
} catch (numberInvalidError) {
|
||||
console.log(numberInvalidError);
|
||||
$('#countrycode').addClass('invalid');
|
||||
$('#number').addClass('invalid');
|
||||
}
|
||||
}
|
||||
|
||||
$('#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;
|
||||
|
@ -50,9 +42,14 @@ $('#code').on('change', function() {
|
|||
var single_device = false;
|
||||
|
||||
$('#init-go-single-client').click(function() {
|
||||
var number = textsecure.utils.verifyNumber($('#number').val(), $('#countrycode').val());
|
||||
try {
|
||||
var parsedNumber = textsecure.utils.verifyNumber($('#number').val(), $('#regionCode').val());
|
||||
} catch(e) {
|
||||
alert("Please enter a valid phone number first.");
|
||||
return false;
|
||||
}
|
||||
|
||||
$('#init-go').html('Setup');
|
||||
$('#init-go').text('Setup');
|
||||
$('#countrycode').prop('disabled', 'disabled');
|
||||
$('#number').prop('disabled', 'disabled');
|
||||
$('#init-go-single-client').prop('disabled', 'disabled');
|
||||
|
@ -60,7 +57,7 @@ $('#init-go-single-client').click(function() {
|
|||
|
||||
single_device = true;
|
||||
|
||||
textsecure.api.requestVerificationCode(number).catch(function(error) {
|
||||
textsecure.api.requestVerificationCode(parsedNumber).catch(function(error) {
|
||||
//TODO: No alerts
|
||||
if (error.humanReadable)
|
||||
alert(error.humanReadable);
|
||||
|
@ -70,7 +67,7 @@ $('#init-go-single-client').click(function() {
|
|||
});
|
||||
|
||||
$('#init-go').click(function() {
|
||||
var number = textsecure.utils.verifyNumber($('#number').val(), $('#countrycode').val());
|
||||
var parsedNumber = textsecure.utils.verifyNumber($('#number').val(), $('#regionCode').val());
|
||||
if (!isCodeValid()) {
|
||||
updateCodeColor();
|
||||
return;
|
||||
|
@ -78,25 +75,25 @@ $('#init-go').click(function() {
|
|||
|
||||
|
||||
$('#init-setup').hide();
|
||||
$('#verify1done').html('');
|
||||
$('#verify1done').text('');
|
||||
$('#verify2').hide();
|
||||
$('#verify3done').html('');
|
||||
$('#verify4done').html('');
|
||||
$('#verify3done').text('');
|
||||
$('#verify4done').text('');
|
||||
$('#verify').show();
|
||||
|
||||
textsecure.register(number, $('#code').val(), single_device, function(step) {
|
||||
textsecure.register(parsedNumber, $('#code').val(), single_device, function(step) {
|
||||
switch(step) {
|
||||
case 1:
|
||||
$('#verify1done').html('done');
|
||||
$('#verify1done').text('done');
|
||||
break;
|
||||
case 2:
|
||||
$('#verify2done').html('done');
|
||||
$('#verify2done').text('done');
|
||||
break;
|
||||
case 3:
|
||||
$('#verify3done').html('done');
|
||||
$('#verify3done').text('done');
|
||||
break;
|
||||
case 4:
|
||||
$('#complete-number').html(number);
|
||||
$('#complete-number').text(parsedNumber);
|
||||
$('#verify').hide();
|
||||
$('#setup-complete').show();
|
||||
registrationDone();
|
||||
|
@ -111,12 +108,37 @@ $('#init-go').click(function() {
|
|||
});
|
||||
|
||||
textsecure.registerOnLoadFunction(function() {
|
||||
$(function() {
|
||||
if (!isRegistrationDone()) {
|
||||
$('#init-setup').show();
|
||||
} else {
|
||||
$('#complete-number').html(textsecure.storage.getUnencrypted("number_id").split(".")[0]);//TODO: no
|
||||
$('#setup-complete').show();
|
||||
$(function() {
|
||||
if (!isRegistrationDone()) {
|
||||
$('#init-setup').show();
|
||||
|
||||
var countrys = textsecure.utils.getAllRegionCodes();
|
||||
$.each(countrys, function (regionCode, countryName) {
|
||||
$('#regionCode').append($('<option>', {
|
||||
value: regionCode,
|
||||
text : countryName
|
||||
}));
|
||||
});
|
||||
|
||||
$('#regionCode').change(function(){
|
||||
$('#countrycode').val(textsecure.utils.getCountryCodeForRegion(this.value));
|
||||
updateNumberColors();
|
||||
});
|
||||
|
||||
$('#countrycode').keyup(function(){
|
||||
$('#regionCode').val(textsecure.utils.getRegionCodeForCountryCode($('#countrycode').val()));
|
||||
updateNumberColors();
|
||||
});
|
||||
|
||||
$('#number').change(updateNumberColors);
|
||||
|
||||
// handle form data cached by the browser (after a page ref
|
||||
$('#regionCode').val(textsecure.utils.getRegionCodeForCountryCode($('#countrycode').val()));
|
||||
updateNumberColors();
|
||||
|
||||
} else {
|
||||
$('#complete-number').text(textsecure.utils.unencodeNumber(textsecure.storage.getUnencrypted("number_id"))[0]);//TODO: no
|
||||
$('#setup-complete').show();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
var splitString = $("#send_numbers").val().split(",");
|
||||
for (var i = 0; i < splitString.length; i++) {
|
||||
try {
|
||||
numbers.push(textsecure.utils.verifyNumber(splitString[i]));
|
||||
numbers.push(textsecure.utils.verifyNumber(splitString[i], textsecure.storage.getUnencrypted("regionCode")));
|
||||
} catch (numberError) {
|
||||
if (!numberError.countryCodeValid) {
|
||||
Whisper.notify('Invalid country code');
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue