diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/telephony/CarrierData.java b/service/src/main/java/org/whispersystems/textsecuregcm/telephony/CarrierData.java index 7e8174975..4d6942e2b 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/telephony/CarrierData.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/telephony/CarrierData.java @@ -9,19 +9,22 @@ import java.util.Optional; /// Line type and home network information for a specific phone number. /// -/// @param carrierName the name of the network operator for the specified phone number -/// @param lineType the line type for the specified phone number -/// @param mcc the mobile country code (MCC) of the phone number's home network if known; may be empty if the -/// phone number is not a mobile number -/// @param mnc the mobile network code (MNC) of the phone number's home network if known; may be empty if the -/// phone number is not a mobile number -/// @param isPorted indicates whether the number has been ported from its original network to another network; may be -/// empty if not known +/// @param carrierName the name of the network operator for the specified phone number +/// @param lineType the line type for the specified phone number +/// @param mcc the mobile country code (MCC) of the phone number's home network if known; may be empty if the +/// phone number is not a mobile number +/// @param mnc the mobile network code (MNC) of the phone number's home network if known; may be empty if the +/// phone number is not a mobile number +/// @param isPorted indicates whether the number has been ported from its original network to another network; may +/// be empty if not known +/// @param isDisposable indicates whether the number is believed to be connected to a service that offers pooled, +/// "disposable" numbers; may be empty if not known public record CarrierData(String carrierName, LineType lineType, Optional mcc, Optional mnc, - Optional isPorted) { + Optional isPorted, + Optional isDisposable) { public enum LineType { MOBILE, diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/telephony/hlrlookup/HlrLookupCarrierDataProvider.java b/service/src/main/java/org/whispersystems/textsecuregcm/telephony/hlrlookup/HlrLookupCarrierDataProvider.java index c8631cf08..b080ee49e 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/telephony/hlrlookup/HlrLookupCarrierDataProvider.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/telephony/hlrlookup/HlrLookupCarrierDataProvider.java @@ -148,7 +148,8 @@ public class HlrLookupCarrierDataProvider implements CarrierDataProvider { lineType(result.telephoneNumberType()), mccFromMccMnc(networkDetails.mccmnc()), mncFromMccMnc(networkDetails.mccmnc()), - isPorted(result.isPorted()))); + isPorted(result.isPorted()), + isDisposableNumber(result.disposableNumber()))); } private static Tag getCreditsSpentTag(final HlrLookupResult hlrLookupResult) { @@ -205,6 +206,15 @@ public class HlrLookupCarrierDataProvider implements CarrierDataProvider { }; } + @VisibleForTesting + static Optional isDisposableNumber(@Nullable final String disposableNumber) { + return switch (disposableNumber) { + case "YES" -> Optional.of(true); + case "NO" -> Optional.of(false); + case null, default -> Optional.empty(); + }; + } + @VisibleForTesting static HlrLookupResponse parseResponse(final String responseJson) throws JsonProcessingException { return OBJECT_MAPPER.readValue(responseJson, HlrLookupResponse.class); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/telephony/hlrlookup/HlrLookupResult.java b/service/src/main/java/org/whispersystems/textsecuregcm/telephony/hlrlookup/HlrLookupResult.java index f21b3f404..08bed7828 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/telephony/hlrlookup/HlrLookupResult.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/telephony/hlrlookup/HlrLookupResult.java @@ -16,5 +16,6 @@ record HlrLookupResult(String error, String currentNetwork, NetworkDetails currentNetworkDetails, String telephoneNumberType, - String isPorted) { + String isPorted, + String disposableNumber) { } diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/storage/VerificationSessionsTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/storage/VerificationSessionsTest.java index dccc4ea5b..a56ec89b5 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/storage/VerificationSessionsTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/storage/VerificationSessionsTest.java @@ -65,7 +65,7 @@ class VerificationSessionsTest { final Optional absentSession = verificationSessions.findForKey(sessionId).join(); assertTrue(absentSession.isEmpty()); - final VerificationSession session = new VerificationSession(sessionId, null, new CarrierData("Test", CarrierData.LineType.MOBILE, Optional.of("123"), Optional.empty(), Optional.empty()), + final VerificationSession session = new VerificationSession(sessionId, null, new CarrierData("Test", CarrierData.LineType.MOBILE, Optional.of("123"), Optional.empty(), Optional.empty(), Optional.empty()), List.of(VerificationSession.Information.PUSH_CHALLENGE), Collections.emptyList(), null, null, true, clock.millis(), clock.millis(), Duration.ofMinutes(1).toSeconds()); @@ -80,7 +80,7 @@ class VerificationSessionsTest { assertInstanceOf(ConditionalCheckFailedException.class, t, "inserting with the same key should fail conditional checks"); - final VerificationSession updatedSession = new VerificationSession(sessionId, null, new CarrierData("Test", CarrierData.LineType.MOBILE, Optional.of("123"), Optional.empty(), Optional.empty()), Collections.emptyList(), + final VerificationSession updatedSession = new VerificationSession(sessionId, null, new CarrierData("Test", CarrierData.LineType.MOBILE, Optional.of("123"), Optional.empty(), Optional.empty(), Optional.empty()), Collections.emptyList(), List.of(VerificationSession.Information.PUSH_CHALLENGE), null, null, true, clock.millis(), clock.millis(), Duration.ofMinutes(2).toSeconds()); verificationSessions.update(sessionId, updatedSession).join(); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/telephony/hlrlookup/HlrLookupCarrierDataProviderTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/telephony/hlrlookup/HlrLookupCarrierDataProviderTest.java index f3eb4be52..fafb2dd53 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/telephony/hlrlookup/HlrLookupCarrierDataProviderTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/telephony/hlrlookup/HlrLookupCarrierDataProviderTest.java @@ -93,6 +93,7 @@ class HlrLookupCarrierDataProviderTest { "country_prefix": "44" }, "is_ported": "YES", + "disposable_number": "NO", "timestamp": "2022-09-08T10:56:03Z", "telephone_number_type": "MOBILE", "sms_email": "", @@ -110,7 +111,7 @@ class HlrLookupCarrierDataProviderTest { final Optional maybeCarrierData = hlrLookupCarrierDataProvider.lookupCarrierData(PhoneNumberUtil.getInstance().getExampleNumber("US"), Duration.ZERO); - assertEquals(Optional.of(new CarrierData("Virgin Mobile", CarrierData.LineType.MOBILE, Optional.of("234"), Optional.of("38"), Optional.of(true))), + assertEquals(Optional.of(new CarrierData("Virgin Mobile", CarrierData.LineType.MOBILE, Optional.of("234"), Optional.of("38"), Optional.of(true), Optional.of(false))), maybeCarrierData); } @@ -224,7 +225,7 @@ class HlrLookupCarrierDataProviderTest { @MethodSource void isPorted(final String isPortedString, final Optional expectedIsPortedValue) { final HlrLookupResult hlrLookupResult = - new HlrLookupResult("NONE", 1.0f, "NOT_AVAILABLE", null, "NOT_AVAILABLE", null, "MOBILE", isPortedString); + new HlrLookupResult("NONE", 1.0f, "NOT_AVAILABLE", null, "NOT_AVAILABLE", null, "MOBILE", isPortedString, null); assertEquals(expectedIsPortedValue, HlrLookupCarrierDataProvider.isPorted(hlrLookupResult.isPorted())); } @@ -291,7 +292,8 @@ class HlrLookupCarrierDataProviderTest { currentNetwork == null ? "NOT_AVAILABLE" : "AVAILABLE", currentNetwork, "MOBILE", - "NO"); + "NO", + "UNKNOWN"); } @Test