diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/sms/TwilioSmsSender.java b/service/src/main/java/org/whispersystems/textsecuregcm/sms/TwilioSmsSender.java index ef9c4ab89..5d0ce35c0 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/sms/TwilioSmsSender.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/sms/TwilioSmsSender.java @@ -76,8 +76,10 @@ public class TwilioSmsSender { private final DynamicConfigurationManager dynamicConfigurationManager; + private final TwilioVerifySender twilioVerifySender; + @VisibleForTesting - public TwilioSmsSender(String baseUri, TwilioConfiguration twilioConfiguration, DynamicConfigurationManager dynamicConfigurationManager) { + public TwilioSmsSender(String baseUri, String baseVerifyUri, TwilioConfiguration twilioConfiguration, DynamicConfigurationManager dynamicConfigurationManager) { Executor executor = ExecutorUtils.newFixedThreadBoundedQueueExecutor(10, 100); this.accountId = twilioConfiguration.getAccountId(); @@ -102,14 +104,17 @@ public class TwilioSmsSender { .withExecutor(executor) .withName("twilio") .build(); + this.dynamicConfigurationManager = dynamicConfigurationManager; + this.twilioVerifySender = new TwilioVerifySender(baseVerifyUri, httpClient, twilioConfiguration); } public TwilioSmsSender(TwilioConfiguration twilioConfiguration, DynamicConfigurationManager dynamicConfigurationManager) { - this("https://api.twilio.com", twilioConfiguration, dynamicConfigurationManager); + this("https://api.twilio.com", "https://verify.twilio.com", twilioConfiguration, dynamicConfigurationManager); } public CompletableFuture deliverSmsVerification(String destination, Optional clientType, String verificationCode) { + Map requestParameters = new HashMap<>(); requestParameters.put("To", destination); requestParameters.put("MessagingServiceSid", "1".equals(Util.getCountryCode(destination)) ? nanpaMessagingServiceSid : messagingServiceSid); @@ -227,6 +232,25 @@ public class TwilioSmsSender { } } + public CompletableFuture> deliverSmsVerificationWithVerify(String destination, Optional clientType, String verificationCode, List languageRanges) { + + smsMeter.mark(); + + return twilioVerifySender.deliverSmsVerificationWithVerify(destination, clientType, verificationCode, languageRanges); + } + + public CompletableFuture> deliverVoxVerificationWithVerify(String destination, String verificationCode, List languageRanges) { + + voxMeter.mark(); + + return twilioVerifySender.deliverVoxVerificationWithVerify(destination, verificationCode, languageRanges); + } + + public CompletableFuture reportVerificationSucceeded(String verificationSid) { + + return twilioVerifySender.reportVerificationSucceeded(verificationSid); + } + public static class TwilioResponse { private TwilioSuccessResponse successResponse; diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/sms/TwilioSmsSenderTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/sms/TwilioSmsSenderTest.java index aececd91a..de2b7843a 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/sms/TwilioSmsSenderTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/sms/TwilioSmsSenderTest.java @@ -5,13 +5,7 @@ package org.whispersystems.textsecuregcm.tests.sms; -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; -import static com.github.tomakehurst.wiremock.client.WireMock.matching; -import static com.github.tomakehurst.wiremock.client.WireMock.post; -import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static com.github.tomakehurst.wiremock.client.WireMock.verify; +import static com.github.tomakehurst.wiremock.client.WireMock.*; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.mockito.Mockito.*; @@ -36,12 +30,14 @@ public class TwilioSmsSenderTest { private static final String ACCOUNT_TOKEN = "test_account_token"; private static final String MESSAGING_SERVICE_SID = "test_messaging_services_id"; private static final String NANPA_MESSAGING_SERVICE_SID = "nanpa_test_messaging_service_id"; + private static final String VERIFY_SERVICE_SID = "verify_service_sid"; private static final String LOCAL_DOMAIN = "test.com"; @Rule public WireMockRule wireMockRule = new WireMockRule(options().dynamicPort().dynamicHttpsPort()); private DynamicConfigurationManager dynamicConfigurationManager; + private TwilioSmsSender sender; @Before public void setup() { @@ -52,6 +48,9 @@ public class TwilioSmsSenderTest { dynamicConfiguration.setTwilioConfiguration(dynamicTwilioConfiguration); dynamicTwilioConfiguration.setNumbers(List.of("+14151111111", "+14152222222")); when(dynamicConfigurationManager.getConfiguration()).thenReturn(dynamicConfiguration); + + TwilioConfiguration configuration = createTwilioConfiguration(); + sender = new TwilioSmsSender("http://localhost:" + wireMockRule.port(), "http://localhost:11111", configuration, dynamicConfigurationManager); } @Nonnull @@ -61,12 +60,14 @@ public class TwilioSmsSenderTest { configuration.setAccountToken(ACCOUNT_TOKEN); configuration.setMessagingServiceSid(MESSAGING_SERVICE_SID); configuration.setNanpaMessagingServiceSid(NANPA_MESSAGING_SERVICE_SID); + configuration.setVerifyServiceSid(VERIFY_SERVICE_SID); configuration.setLocalDomain(LOCAL_DOMAIN); configuration.setIosVerificationText("Verify on iOS: %1$s\n\nsomelink://verify/%1$s"); configuration.setAndroidNgVerificationText("<#> Verify on AndroidNg: %1$s\n\ncharacters"); configuration.setAndroid202001VerificationText("Verify on Android202001: %1$s\n\nsomelink://verify/%1$s\n\ncharacters"); configuration.setAndroid202103VerificationText("Verify on Android202103: %1$s\n\ncharacters"); configuration.setGenericVerificationText("Verify on whatever: %1$s"); + configuration.setAndroidAppHash("someHash"); return configuration; } @@ -81,9 +82,8 @@ public class TwilioSmsSenderTest { @Test public void testSendSms() { setupSuccessStubForSms(); - TwilioConfiguration configuration = createTwilioConfiguration(); - TwilioSmsSender sender = new TwilioSmsSender("http://localhost:" + wireMockRule.port(), configuration, dynamicConfigurationManager); - boolean success = sender.deliverSmsVerification("+14153333333", Optional.of("android-ng"), "123-456").join(); + + boolean success = sender.deliverSmsVerification("+14153333333", Optional.of("android-ng"), "123-456").join(); assertThat(success).isTrue(); @@ -95,8 +95,7 @@ public class TwilioSmsSenderTest { @Test public void testSendSmsAndroid202001() { setupSuccessStubForSms(); - TwilioConfiguration configuration = createTwilioConfiguration(); - TwilioSmsSender sender = new TwilioSmsSender("http://localhost:" + wireMockRule.port(), configuration, dynamicConfigurationManager); + boolean success = sender.deliverSmsVerification("+14153333333", Optional.of("android-2020-01"), "123-456").join(); assertThat(success).isTrue(); @@ -109,8 +108,7 @@ public class TwilioSmsSenderTest { @Test public void testSendSmsAndroid202103() { setupSuccessStubForSms(); - TwilioConfiguration configuration = createTwilioConfiguration(); - TwilioSmsSender sender = new TwilioSmsSender("http://localhost:" + wireMockRule.port(), configuration, dynamicConfigurationManager); + boolean success = sender.deliverSmsVerification("+14153333333", Optional.of("android-2021-03"), "123456").join(); assertThat(success).isTrue(); @@ -125,7 +123,9 @@ public class TwilioSmsSenderTest { setupSuccessStubForSms(); TwilioConfiguration configuration = createTwilioConfiguration(); configuration.setNanpaMessagingServiceSid(NANPA_MESSAGING_SERVICE_SID); - TwilioSmsSender sender = new TwilioSmsSender("http://localhost:" + wireMockRule.port(), configuration, dynamicConfigurationManager); + + TwilioSmsSender sender = new TwilioSmsSender("http://localhost:" + wireMockRule.port(), + "http://localhost:11111", configuration, dynamicConfigurationManager); assertThat(sender.deliverSmsVerification("+14153333333", Optional.of("ios"), "654-321").join()).isTrue(); verify(1, postRequestedFor(urlEqualTo("/2010-04-01/Accounts/" + ACCOUNT_ID + "/Messages.json")) @@ -147,11 +147,7 @@ public class TwilioSmsSenderTest { .withHeader("Content-Type", "application/json") .withBody("{\"price\": -0.00750, \"status\": \"completed\"}"))); - - TwilioConfiguration configuration = createTwilioConfiguration(); - - TwilioSmsSender sender = new TwilioSmsSender("http://localhost:" + wireMockRule.port(), configuration, dynamicConfigurationManager); - boolean success = sender.deliverVoxVerification("+14153333333", "123-456", LanguageRange.parse("en-US")).join(); + boolean success = sender.deliverVoxVerification("+14153333333", "123-456", LanguageRange.parse("en-US")).join(); assertThat(success).isTrue(); @@ -168,11 +164,7 @@ public class TwilioSmsSenderTest { .withHeader("Content-Type", "application/json") .withBody("{\"price\": -0.00750, \"status\": \"completed\"}"))); - - TwilioConfiguration configuration = createTwilioConfiguration(); - - TwilioSmsSender sender = new TwilioSmsSender("http://localhost:" + wireMockRule.port(), configuration, dynamicConfigurationManager); - boolean success = sender.deliverVoxVerification("+14153333333", "123-456", LanguageRange.parse("en-US;q=1, ar-US;q=0.9, fa-US;q=0.8, zh-Hans-US;q=0.7, ru-RU;q=0.6, zh-Hant-US;q=0.5")).join(); + boolean success = sender.deliverVoxVerification("+14153333333", "123-456", LanguageRange.parse("en-US;q=1, ar-US;q=0.9, fa-US;q=0.8, zh-Hans-US;q=0.7, ru-RU;q=0.6, zh-Hant-US;q=0.5")).join(); assertThat(success).isTrue(); @@ -190,11 +182,7 @@ public class TwilioSmsSenderTest { .withHeader("Content-Type", "application/json") .withBody("{\"message\": \"Server error!\"}"))); - - TwilioConfiguration configuration = createTwilioConfiguration(); - - TwilioSmsSender sender = new TwilioSmsSender("http://localhost:" + wireMockRule.port(), configuration, dynamicConfigurationManager); - boolean success = sender.deliverSmsVerification("+14153333333", Optional.of("android-ng"), "123-456").join(); + boolean success = sender.deliverSmsVerification("+14153333333", Optional.of("android-ng"), "123-456").join(); assertThat(success).isFalse(); @@ -212,10 +200,7 @@ public class TwilioSmsSenderTest { .withHeader("Content-Type", "application/json") .withBody("{\"message\": \"Server error!\"}"))); - TwilioConfiguration configuration = createTwilioConfiguration(); - - TwilioSmsSender sender = new TwilioSmsSender("http://localhost:" + wireMockRule.port(), configuration, dynamicConfigurationManager); - boolean success = sender.deliverVoxVerification("+14153333333", "123-456", LanguageRange.parse("en-US")).join(); + boolean success = sender.deliverVoxVerification("+14153333333", "123-456", LanguageRange.parse("en-US")).join(); assertThat(success).isFalse(); @@ -228,9 +213,9 @@ public class TwilioSmsSenderTest { @Test public void testSendSmsNetworkFailure() { TwilioConfiguration configuration = createTwilioConfiguration(); + TwilioSmsSender sender = new TwilioSmsSender("http://localhost:" + 39873, "http://localhost:" + 39873, configuration, dynamicConfigurationManager); - TwilioSmsSender sender = new TwilioSmsSender("http://localhost:" + 39873, configuration, dynamicConfigurationManager); - boolean success = sender.deliverSmsVerification("+14153333333", Optional.of("android-ng"), "123-456").join(); + boolean success = sender.deliverSmsVerification("+14153333333", Optional.of("android-ng"), "123-456").join(); assertThat(success).isFalse(); } @@ -244,10 +229,7 @@ public class TwilioSmsSenderTest { .withHeader("Content-Type", "application/json") .withBody("{\"status\": 400, \"message\": \"is not currently reachable\", \"code\": 21612}"))); - TwilioConfiguration configuration = createTwilioConfiguration(); - - TwilioSmsSender sender = new TwilioSmsSender("http://localhost:" + wireMockRule.port(), configuration, dynamicConfigurationManager); - boolean success = sender.deliverSmsVerification("+14153333333", Optional.of("android-ng"), "123-456").join(); + boolean success = sender.deliverSmsVerification("+14153333333", Optional.of("android-ng"), "123-456").join(); assertThat(success).isFalse(); @@ -259,8 +241,7 @@ public class TwilioSmsSenderTest { @Test public void testSendSmsChina() { setupSuccessStubForSms(); - TwilioConfiguration configuration = createTwilioConfiguration(); - TwilioSmsSender sender = new TwilioSmsSender("http://localhost:" + wireMockRule.port(), configuration, dynamicConfigurationManager); + boolean success = sender.deliverSmsVerification("+861065529988", Optional.of("android-ng"), "123-456").join(); assertThat(success).isTrue();