From 06ca5f14fc32c9e3926727b26068e75b5b95ba85 Mon Sep 17 00:00:00 2001 From: Jon Chambers Date: Mon, 22 Feb 2021 16:01:26 -0500 Subject: [PATCH] Record the age of accounts that send unsealed-sender messages. --- .../textsecuregcm/WhisperServerService.java | 2 +- .../controllers/MessageController.java | 30 ++++++++++++++++++- .../controllers/MessageControllerTest.java | 6 ++-- .../textsecuregcm/tests/util/AuthHelper.java | 5 ++++ 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java b/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java index 300a491ff..8a248015b 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java @@ -402,7 +402,7 @@ public class WhisperServerService extends Application { + metricsCluster.useCluster(connection -> { + if (connection.sync().pfadd(SENT_FIRST_UNSEALED_SENDER_MESSAGE_KEY, source.get().getUuid().toString()) == 1) { + final List tags = List.of( + UserAgentTagUtil.getPlatformTag(userAgent), + Tag.of(SENDER_COUNTRY_TAG_NAME, Util.getCountryCode(source.get().getNumber()))); + + assert source.get().getMasterDevice().isPresent(); + + final long accountAge = System.currentTimeMillis() - source.get().getMasterDevice().get().getCreated(); + + DistributionSummary.builder(UNSEALED_SENDER_ACCOUNT_AGE_DISTRIBUTION_NAME) + .tags(tags) + .publishPercentileHistogram() + .register(Metrics.globalRegistry) + .record(accountAge); + } + }); + }); + try { rateLimiters.getUnsealedSenderLimiter().validate(source.get().getUuid().toString(), destinationName.toString()); } catch (RateLimitExceededException e) { diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/MessageControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/MessageControllerTest.java index 57643750a..d285e5270 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/MessageControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/MessageControllerTest.java @@ -29,7 +29,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.ImmutableSet; import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider; import io.dropwizard.testing.junit.ResourceTestRule; -import java.io.IOException; import java.util.HashSet; import java.util.LinkedList; import java.util.List; @@ -44,7 +43,6 @@ import junitparams.JUnitParamsRunner; import junitparams.Parameters; import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory; import org.junit.Before; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -67,6 +65,7 @@ import org.whispersystems.textsecuregcm.limits.RateLimiters; import org.whispersystems.textsecuregcm.push.ApnFallbackManager; import org.whispersystems.textsecuregcm.push.MessageSender; import org.whispersystems.textsecuregcm.push.ReceiptSender; +import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster; import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.AccountsManager; import org.whispersystems.textsecuregcm.storage.Device; @@ -93,6 +92,7 @@ public class MessageControllerTest { private final CardinalityRateLimiter unsealedSenderLimiter = mock(CardinalityRateLimiter.class); private final ApnFallbackManager apnFallbackManager = mock(ApnFallbackManager.class); private final DynamicConfigurationManager dynamicConfigurationManager = mock(DynamicConfigurationManager.class); + private final FaultTolerantRedisCluster metricsCluster = mock(FaultTolerantRedisCluster.class); private final ObjectMapper mapper = new ObjectMapper(); @@ -102,7 +102,7 @@ public class MessageControllerTest { .addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(ImmutableSet.of(Account.class, DisabledPermittedAccount.class))) .setTestContainerFactory(new GrizzlyWebTestContainerFactory()) .addResource(new MessageController(rateLimiters, messageSender, receiptSender, accountsManager, - messagesManager, apnFallbackManager, dynamicConfigurationManager)) + messagesManager, apnFallbackManager, dynamicConfigurationManager, metricsCluster)) .build(); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/util/AuthHelper.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/util/AuthHelper.java index db9663e1e..316f93a80 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/util/AuthHelper.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/util/AuthHelper.java @@ -101,9 +101,13 @@ public class AuthHelper { when(UNDISCOVERABLE_DEVICE.isMaster()).thenReturn(true); when(VALID_ACCOUNT.getDevice(1L)).thenReturn(Optional.of(VALID_DEVICE)); + when(VALID_ACCOUNT.getMasterDevice()).thenReturn(Optional.of(VALID_DEVICE)); when(VALID_ACCOUNT_TWO.getDevice(eq(1L))).thenReturn(Optional.of(VALID_DEVICE_TWO)); + when(VALID_ACCOUNT_TWO.getMasterDevice()).thenReturn(Optional.of(VALID_DEVICE_TWO)); when(DISABLED_ACCOUNT.getDevice(eq(1L))).thenReturn(Optional.of(DISABLED_DEVICE)); + when(DISABLED_ACCOUNT.getMasterDevice()).thenReturn(Optional.of(DISABLED_DEVICE)); when(UNDISCOVERABLE_ACCOUNT.getDevice(eq(1L))).thenReturn(Optional.of(UNDISCOVERABLE_DEVICE)); + when(UNDISCOVERABLE_ACCOUNT.getMasterDevice()).thenReturn(Optional.of(UNDISCOVERABLE_DEVICE)); when(VALID_ACCOUNT_TWO.getEnabledDeviceCount()).thenReturn(6); @@ -211,6 +215,7 @@ public class AuthHelper { when(device.getId()).thenReturn(1L); when(device.isEnabled()).thenReturn(true); when(account.getDevice(1L)).thenReturn(Optional.of(device)); + when(account.getMasterDevice()).thenReturn(Optional.of(device)); when(account.getNumber()).thenReturn(number); when(account.getUuid()).thenReturn(uuid); when(account.getAuthenticatedDevice()).thenReturn(Optional.of(device));