From 06eb890761598c3de842efea102f481fb4167767 Mon Sep 17 00:00:00 2001 From: Chris Eager Date: Wed, 10 Aug 2022 12:24:01 -0500 Subject: [PATCH] Improve e164 normalization check by re-parsing without country code --- .../textsecuregcm/util/Util.java | 27 ++++++++++++++++--- .../tests/util/ValidNumberTest.java | 6 ++++- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/util/Util.java b/service/src/main/java/org/whispersystems/textsecuregcm/util/Util.java index 482e6352a..413327330 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/util/Util.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/util/Util.java @@ -42,11 +42,30 @@ public class Util { } try { - final PhoneNumber phoneNumber = PHONE_NUMBER_UTIL.parse(number, null); - final String normalizedNumber = PHONE_NUMBER_UTIL.format(phoneNumber, PhoneNumberFormat.E164); + final PhoneNumber inputNumber = PHONE_NUMBER_UTIL.parse(number, null); - if (!number.equals(normalizedNumber)) { - throw new NonNormalizedPhoneNumberException(number, normalizedNumber); + // For normalization, we want to format from a version parsed with the country code removed. + // This handles some cases of "possible", but non-normalized input numbers with a doubled country code, that is + // with the format "+{country code} {country code} {national number}" + final int countryCode = inputNumber.getCountryCode(); + final String region = PHONE_NUMBER_UTIL.getRegionCodeForCountryCode(countryCode); + + final PhoneNumber normalizedNumber = switch (region) { + // the country code has no associated region. Be lenient (and simple) and accept the input number + case "ZZ", "001" -> inputNumber; + default -> { + final String maybeLeadingZero = + inputNumber.hasItalianLeadingZero() && inputNumber.isItalianLeadingZero() ? "0" : ""; + yield PHONE_NUMBER_UTIL.parse( + maybeLeadingZero + inputNumber.getNationalNumber(), region); + } + }; + + final String normalizedE164 = PHONE_NUMBER_UTIL.format(normalizedNumber, + PhoneNumberFormat.E164); + + if (!number.equals(normalizedE164)) { + throw new NonNormalizedPhoneNumberException(number, normalizedE164); } } catch (final NumberParseException e) { throw new ImpossiblePhoneNumberException(e); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/util/ValidNumberTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/util/ValidNumberTest.java index 669794aad..1780c8688 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/util/ValidNumberTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/util/ValidNumberTest.java @@ -24,11 +24,13 @@ class ValidNumberTest { "+71234567890", "+447535742222", "+4915174108888", + "+2250707312345", "+298123456", "+299123456", "+376123456", "+68512345", - "+689123456"}) + "+689123456", + "+80011111111"}) void requireNormalizedNumber(final String number) { assertDoesNotThrow(() -> Util.requireNormalizedNumber(number)); } @@ -56,6 +58,8 @@ class ValidNumberTest { @ParameterizedTest @ValueSource(strings = { "+4407700900111", + "+49493023125000", // double country code - this e164 is "possible" + "+494915110000000", // double country code - this e164 is "possible" and "valid" "+1 415 123 1234", "+1 (415) 123-1234", "+1 415)123-1234",