Add a method for verifying that numbers are normalized in addition to being dialable
This commit is contained in:
parent
a3fe4b9980
commit
7762afc497
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013-2021 Signal Messenger, LLC
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.whispersystems.textsecuregcm.util;
|
||||||
|
|
||||||
|
public class ImpossibleNumberException extends Exception {
|
||||||
|
|
||||||
|
public ImpossibleNumberException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImpossibleNumberException(final Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013-2021 Signal Messenger, LLC
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.whispersystems.textsecuregcm.util;
|
||||||
|
|
||||||
|
public class NonNormalizedNumberException extends Exception {
|
||||||
|
|
||||||
|
private final String originalNumber;
|
||||||
|
private final String normalizedNumber;
|
||||||
|
|
||||||
|
public NonNormalizedNumberException(final String originalNumber, final String normalizedNumber) {
|
||||||
|
this.originalNumber = originalNumber;
|
||||||
|
this.normalizedNumber = normalizedNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOriginalNumber() {
|
||||||
|
return originalNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNormalizedNumber() {
|
||||||
|
return normalizedNumber;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,10 @@
|
||||||
*/
|
*/
|
||||||
package org.whispersystems.textsecuregcm.util;
|
package org.whispersystems.textsecuregcm.util;
|
||||||
|
|
||||||
|
import com.google.i18n.phonenumbers.NumberParseException;
|
||||||
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
||||||
|
import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;
|
||||||
|
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
|
@ -28,6 +31,8 @@ public class Util {
|
||||||
|
|
||||||
private static final Pattern COUNTRY_CODE_PATTERN = Pattern.compile("^\\+([17]|2[07]|3[0123469]|4[013456789]|5[12345678]|6[0123456]|8[1246]|9[0123458]|\\d{3})");
|
private static final Pattern COUNTRY_CODE_PATTERN = Pattern.compile("^\\+([17]|2[07]|3[0123469]|4[013456789]|5[12345678]|6[0123456]|8[1246]|9[0123458]|\\d{3})");
|
||||||
|
|
||||||
|
private static final PhoneNumberUtil PHONE_NUMBER_UTIL = PhoneNumberUtil.getInstance();
|
||||||
|
|
||||||
public static byte[] getContactToken(String number) {
|
public static byte[] getContactToken(String number) {
|
||||||
try {
|
try {
|
||||||
MessageDigest digest = MessageDigest.getInstance("SHA1");
|
MessageDigest digest = MessageDigest.getInstance("SHA1");
|
||||||
|
@ -41,7 +46,32 @@ public class Util {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isValidNumber(String number) {
|
public static boolean isValidNumber(String number) {
|
||||||
return number.matches("^\\+[0-9]+") && PhoneNumberUtil.getInstance().isPossibleNumber(number, null);
|
return number.matches("^\\+[0-9]+") && PHONE_NUMBER_UTIL.isPossibleNumber(number, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that the given number is a valid, E164-normalized phone number.
|
||||||
|
*
|
||||||
|
* @param number the number to check
|
||||||
|
*
|
||||||
|
* @throws ImpossibleNumberException if the given number is not a valid phone number at all
|
||||||
|
* @throws NonNormalizedNumberException if the given number is a valid phone number, but isn't E164-normalized
|
||||||
|
*/
|
||||||
|
public static void requireNormalizedNumber(final String number) throws ImpossibleNumberException, NonNormalizedNumberException {
|
||||||
|
if (!PHONE_NUMBER_UTIL.isPossibleNumber(number, null)) {
|
||||||
|
throw new ImpossibleNumberException();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final PhoneNumber phoneNumber = PHONE_NUMBER_UTIL.parse(number, null);
|
||||||
|
final String normalizedNumber = PHONE_NUMBER_UTIL.format(phoneNumber, PhoneNumberFormat.E164);
|
||||||
|
|
||||||
|
if (!number.equals(normalizedNumber)) {
|
||||||
|
throw new NonNormalizedNumberException(number, normalizedNumber);
|
||||||
|
}
|
||||||
|
} catch (final NumberParseException e) {
|
||||||
|
throw new ImpossibleNumberException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getCountryCode(String number) {
|
public static String getCountryCode(String number) {
|
||||||
|
|
|
@ -5,14 +5,20 @@
|
||||||
|
|
||||||
package org.whispersystems.textsecuregcm.tests.util;
|
package org.whispersystems.textsecuregcm.tests.util;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.Arguments;
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
import org.junit.jupiter.params.provider.MethodSource;
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
import org.whispersystems.textsecuregcm.util.ImpossibleNumberException;
|
||||||
|
import org.whispersystems.textsecuregcm.util.NonNormalizedNumberException;
|
||||||
import org.whispersystems.textsecuregcm.util.Util;
|
import org.whispersystems.textsecuregcm.util.Util;
|
||||||
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
class ValidNumberTest {
|
class ValidNumberTest {
|
||||||
|
|
||||||
|
@ -53,4 +59,51 @@ class ValidNumberTest {
|
||||||
Arguments.of("+689123456", true)
|
Arguments.of("+689123456", true)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@ValueSource(strings = {
|
||||||
|
"+447700900111",
|
||||||
|
"+14151231234",
|
||||||
|
"+71234567890",
|
||||||
|
"+447535742222",
|
||||||
|
"+4915174108888",
|
||||||
|
"+298123456",
|
||||||
|
"+299123456",
|
||||||
|
"+376123456",
|
||||||
|
"+68512345",
|
||||||
|
"+689123456"})
|
||||||
|
void requireNormalizedNumber(final String number) {
|
||||||
|
assertDoesNotThrow(() -> Util.requireNormalizedNumber(number));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void requireNormalizedNumberNull() {
|
||||||
|
assertThrows(ImpossibleNumberException.class, () -> Util.requireNormalizedNumber(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@ValueSource(strings = {
|
||||||
|
"Definitely not a phone number at all",
|
||||||
|
"+141512312341",
|
||||||
|
"+712345678901",
|
||||||
|
"+4475357422221",
|
||||||
|
"+491517410888811111",
|
||||||
|
"71234567890",
|
||||||
|
"001447535742222",
|
||||||
|
"+1415123123a"
|
||||||
|
})
|
||||||
|
void requireNormalizedNumberImpossibleNumber(final String number) {
|
||||||
|
assertThrows(ImpossibleNumberException.class, () -> Util.requireNormalizedNumber(number));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@ValueSource(strings = {
|
||||||
|
"+4407700900111",
|
||||||
|
"+1 415 123 1234",
|
||||||
|
"+1 (415) 123-1234",
|
||||||
|
"+1 415)123-1234",
|
||||||
|
" +14151231234"})
|
||||||
|
void requireNormalizedNumberNonNormalized(final String number) {
|
||||||
|
assertThrows(NonNormalizedNumberException.class, () -> Util.requireNormalizedNumber(number));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue