Retire `ReportSpamTokenHandler` interface in favor of `ReportedMessageListener`
This commit is contained in:
parent
4a2768b81d
commit
38a0737afb
|
@ -70,11 +70,6 @@ import org.signal.libsignal.zkgroup.receipts.ServerZkReceiptOperations;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.whispersystems.dispatch.DispatchManager;
|
||||
import org.whispersystems.textsecuregcm.spam.SpamFilter;
|
||||
import org.whispersystems.textsecuregcm.spam.FilterSpam;
|
||||
import org.whispersystems.textsecuregcm.spam.RateLimitChallengeListener;
|
||||
import org.whispersystems.textsecuregcm.spam.ReportSpamTokenHandler;
|
||||
import org.whispersystems.textsecuregcm.spam.ReportSpamTokenProvider;
|
||||
import org.whispersystems.textsecuregcm.auth.AccountAuthenticator;
|
||||
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||
import org.whispersystems.textsecuregcm.auth.CertificateGenerator;
|
||||
|
@ -168,6 +163,10 @@ import org.whispersystems.textsecuregcm.s3.PolicySigner;
|
|||
import org.whispersystems.textsecuregcm.s3.PostPolicyGenerator;
|
||||
import org.whispersystems.textsecuregcm.securebackup.SecureBackupClient;
|
||||
import org.whispersystems.textsecuregcm.securestorage.SecureStorageClient;
|
||||
import org.whispersystems.textsecuregcm.spam.FilterSpam;
|
||||
import org.whispersystems.textsecuregcm.spam.RateLimitChallengeListener;
|
||||
import org.whispersystems.textsecuregcm.spam.ReportSpamTokenProvider;
|
||||
import org.whispersystems.textsecuregcm.spam.SpamFilter;
|
||||
import org.whispersystems.textsecuregcm.sqs.DirectoryQueue;
|
||||
import org.whispersystems.textsecuregcm.storage.AccountCleaner;
|
||||
import org.whispersystems.textsecuregcm.storage.AccountDatabaseCrawler;
|
||||
|
@ -679,7 +678,6 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
|||
|
||||
boolean registeredSpamFilter = false;
|
||||
ReportSpamTokenProvider reportSpamTokenProvider = null;
|
||||
ReportSpamTokenHandler reportSpamTokenHandler = null;
|
||||
|
||||
for (final SpamFilter filter : ServiceLoader.load(SpamFilter.class)) {
|
||||
if (filter.getClass().isAnnotationPresent(FilterSpam.class)) {
|
||||
|
@ -693,12 +691,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
|||
log.info("Multiple spam report token providers found. Using the first.");
|
||||
}
|
||||
|
||||
ReportSpamTokenHandler thisHandler = filter.getReportSpamTokenHandler();
|
||||
if (reportSpamTokenHandler == null) {
|
||||
reportSpamTokenHandler = thisHandler;
|
||||
} else if (thisProvider != null) {
|
||||
log.info("Multiple spam report token handlers found. Using the first.");
|
||||
}
|
||||
filter.getReportedMessageListeners().forEach(reportMessageManager::addListener);
|
||||
|
||||
environment.lifecycle().manage(filter);
|
||||
environment.jersey().register(filter);
|
||||
|
@ -728,10 +721,6 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
|||
reportSpamTokenProvider = ReportSpamTokenProvider.noop();
|
||||
}
|
||||
|
||||
if (reportSpamTokenHandler == null) {
|
||||
reportSpamTokenHandler = ReportSpamTokenHandler.noop();
|
||||
}
|
||||
|
||||
final List<Object> commonControllers = Lists.newArrayList(
|
||||
new ArtController(rateLimiters, artCredentialsGenerator),
|
||||
new AttachmentControllerV2(rateLimiters, config.getAwsAttachmentsConfiguration().getAccessKey(), config.getAwsAttachmentsConfiguration().getAccessSecret(), config.getAwsAttachmentsConfiguration().getRegion(), config.getAwsAttachmentsConfiguration().getBucket()),
|
||||
|
@ -744,7 +733,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
|||
new DonationController(clock, zkReceiptOperations, redeemedReceiptsManager, accountsManager, config.getBadges(),
|
||||
ReceiptCredentialPresentation::new),
|
||||
new MessageController(rateLimiters, messageSender, receiptSender, accountsManager, deletedAccountsManager, messagesManager, pushNotificationManager, reportMessageManager, multiRecipientMessageExecutor,
|
||||
reportSpamTokenProvider, reportSpamTokenHandler),
|
||||
reportSpamTokenProvider),
|
||||
new PaymentsController(currencyManager, paymentsCredentialsGenerator),
|
||||
new ProfileController(clock, rateLimiters, accountsManager, profilesManager, dynamicConfigurationManager,
|
||||
profileBadgeConverter, config.getBadges(), cdnS3Client, profileCdnPolicyGenerator, profileCdnPolicySigner,
|
||||
|
|
|
@ -62,9 +62,6 @@ import javax.ws.rs.core.Response;
|
|||
import javax.ws.rs.core.Response.Status;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.whispersystems.textsecuregcm.spam.FilterSpam;
|
||||
import org.whispersystems.textsecuregcm.spam.ReportSpamTokenHandler;
|
||||
import org.whispersystems.textsecuregcm.spam.ReportSpamTokenProvider;
|
||||
import org.whispersystems.textsecuregcm.auth.Anonymous;
|
||||
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||
import org.whispersystems.textsecuregcm.auth.CombinedUnidentifiedSenderAccessKeys;
|
||||
|
@ -92,6 +89,8 @@ import org.whispersystems.textsecuregcm.push.MessageSender;
|
|||
import org.whispersystems.textsecuregcm.push.NotPushRegisteredException;
|
||||
import org.whispersystems.textsecuregcm.push.PushNotificationManager;
|
||||
import org.whispersystems.textsecuregcm.push.ReceiptSender;
|
||||
import org.whispersystems.textsecuregcm.spam.FilterSpam;
|
||||
import org.whispersystems.textsecuregcm.spam.ReportSpamTokenProvider;
|
||||
import org.whispersystems.textsecuregcm.storage.Account;
|
||||
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||
import org.whispersystems.textsecuregcm.storage.DeletedAccountsManager;
|
||||
|
@ -123,7 +122,6 @@ public class MessageController {
|
|||
private final ReportMessageManager reportMessageManager;
|
||||
private final ExecutorService multiRecipientMessageExecutor;
|
||||
private final ReportSpamTokenProvider reportSpamTokenProvider;
|
||||
private final ReportSpamTokenHandler reportSpamTokenHandler;
|
||||
|
||||
private static final String REJECT_OVERSIZE_MESSAGE_COUNTER = name(MessageController.class, "rejectOversizeMessage");
|
||||
private static final String SENT_MESSAGE_COUNTER_NAME = name(MessageController.class, "sentMessages");
|
||||
|
@ -131,7 +129,6 @@ public class MessageController {
|
|||
private static final String OUTGOING_MESSAGE_LIST_SIZE_BYTES_DISTRIBUTION_NAME = name(MessageController.class, "outgoingMessageListSizeBytes");
|
||||
private static final String RATE_LIMITED_MESSAGE_COUNTER_NAME = name(MessageController.class, "rateLimitedMessage");
|
||||
private static final String REJECT_INVALID_ENVELOPE_TYPE = name(MessageController.class, "rejectInvalidEnvelopeType");
|
||||
private static final String REPORT_SPAM_TOKENS_RECEIVED_COUNTER_NAME = name(MessageController.class, "reportSpamTokensReceived");
|
||||
|
||||
private static final String EPHEMERAL_TAG_NAME = "ephemeral";
|
||||
private static final String SENDER_TYPE_TAG_NAME = "senderType";
|
||||
|
@ -156,8 +153,7 @@ public class MessageController {
|
|||
PushNotificationManager pushNotificationManager,
|
||||
ReportMessageManager reportMessageManager,
|
||||
@Nonnull ExecutorService multiRecipientMessageExecutor,
|
||||
@Nonnull ReportSpamTokenProvider reportSpamTokenProvider,
|
||||
@Nonnull ReportSpamTokenHandler reportSpamTokenHandler) {
|
||||
@Nonnull ReportSpamTokenProvider reportSpamTokenProvider) {
|
||||
this.rateLimiters = rateLimiters;
|
||||
this.messageSender = messageSender;
|
||||
this.receiptSender = receiptSender;
|
||||
|
@ -168,8 +164,6 @@ public class MessageController {
|
|||
this.reportMessageManager = reportMessageManager;
|
||||
this.multiRecipientMessageExecutor = Objects.requireNonNull(multiRecipientMessageExecutor);
|
||||
this.reportSpamTokenProvider = reportSpamTokenProvider;
|
||||
this.reportSpamTokenHandler = reportSpamTokenHandler;
|
||||
|
||||
}
|
||||
|
||||
@Timed
|
||||
|
@ -646,10 +640,6 @@ public class MessageController {
|
|||
final Optional<byte[]> maybeSpamReportToken =
|
||||
spamReport != null ? Optional.of(spamReport.token()) : Optional.empty();
|
||||
|
||||
// fire-and-forget: we don't want to block the response on this action.
|
||||
CompletableFuture<Boolean> ignored =
|
||||
reportSpamTokenHandler.handle(sourceNumber, sourceAci, sourcePni, messageGuid, spamReporterUuid, maybeSpamReportToken.orElse(null));
|
||||
|
||||
reportMessageManager.report(sourceNumber, sourceAci, sourcePni, messageGuid, spamReporterUuid, maybeSpamReportToken);
|
||||
|
||||
return Response.status(Status.ACCEPTED)
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
package org.whispersystems.textsecuregcm.spam;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* Handles ReportSpamTokens during spam reports.
|
||||
*/
|
||||
public interface ReportSpamTokenHandler {
|
||||
|
||||
/**
|
||||
* Handle spam reports using the given ReportSpamToken and other provided parameters.
|
||||
*
|
||||
* @param reportSpamToken binary data representing a spam report token.
|
||||
* @return true if the token could be handled (and was), false otherwise.
|
||||
*/
|
||||
CompletableFuture<Boolean> handle(
|
||||
Optional<String> sourceNumber,
|
||||
Optional<UUID> sourceAci,
|
||||
Optional<UUID> sourcePni,
|
||||
UUID messageGuid,
|
||||
UUID spamReporterUuid,
|
||||
byte[] reportSpamToken);
|
||||
|
||||
/**
|
||||
* Handler which does nothing.
|
||||
*
|
||||
* @return the handler
|
||||
*/
|
||||
static ReportSpamTokenHandler noop() {
|
||||
return new ReportSpamTokenHandler() {
|
||||
@Override
|
||||
public CompletableFuture<Boolean> handle(
|
||||
final Optional<String> sourceNumber,
|
||||
final Optional<UUID> sourceAci,
|
||||
final Optional<UUID> sourcePni,
|
||||
final UUID messageGuid,
|
||||
final UUID spamReporterUuid,
|
||||
final byte[] reportSpamToken) {
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -6,8 +6,10 @@
|
|||
package org.whispersystems.textsecuregcm.spam;
|
||||
|
||||
import io.dropwizard.lifecycle.Managed;
|
||||
import org.whispersystems.textsecuregcm.storage.ReportedMessageListener;
|
||||
import javax.ws.rs.container.ContainerRequestFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A spam filter is a {@link ContainerRequestFilter} that filters requests to message-sending endpoints to
|
||||
|
@ -39,10 +41,10 @@ public interface SpamFilter extends ContainerRequestFilter, Managed {
|
|||
ReportSpamTokenProvider getReportSpamTokenProvider();
|
||||
|
||||
/**
|
||||
* Builds a spam report token handler. This will handle tokens received by the spam reporting system.
|
||||
* Return any and all reported message listeners controlled by the spam filter. Listeners will be registered with the
|
||||
* {@link org.whispersystems.textsecuregcm.storage.ReportMessageManager}.
|
||||
*
|
||||
* @return the configured spam report token handler
|
||||
* @return a list of reported message listeners controlled by the spam filter
|
||||
*/
|
||||
ReportSpamTokenHandler getReportSpamTokenHandler();
|
||||
|
||||
List<ReportedMessageListener> getReportedMessageListeners();
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ package org.whispersystems.textsecuregcm.controllers;
|
|||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
@ -19,7 +18,6 @@ import static org.mockito.ArgumentMatchers.eq;
|
|||
import static org.mockito.Mockito.anyBoolean;
|
||||
import static org.mockito.Mockito.anyString;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.clearInvocations;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.reset;
|
||||
|
@ -68,9 +66,6 @@ import org.junit.jupiter.params.ParameterizedTest;
|
|||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.ArgumentMatcher;
|
||||
import org.whispersystems.textsecuregcm.spam.ReportSpamTokenHandler;
|
||||
import org.whispersystems.textsecuregcm.spam.ReportSpamTokenProvider;
|
||||
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount;
|
||||
import org.whispersystems.textsecuregcm.auth.OptionalAccess;
|
||||
|
@ -94,6 +89,7 @@ import org.whispersystems.textsecuregcm.providers.MultiRecipientMessageProvider;
|
|||
import org.whispersystems.textsecuregcm.push.MessageSender;
|
||||
import org.whispersystems.textsecuregcm.push.PushNotificationManager;
|
||||
import org.whispersystems.textsecuregcm.push.ReceiptSender;
|
||||
import org.whispersystems.textsecuregcm.spam.ReportSpamTokenProvider;
|
||||
import org.whispersystems.textsecuregcm.storage.Account;
|
||||
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||
import org.whispersystems.textsecuregcm.storage.DeletedAccountsManager;
|
||||
|
@ -144,7 +140,6 @@ class MessageControllerTest {
|
|||
private static final PushNotificationManager pushNotificationManager = mock(PushNotificationManager.class);
|
||||
private static final ReportMessageManager reportMessageManager = mock(ReportMessageManager.class);
|
||||
private static final ExecutorService multiRecipientMessageExecutor = mock(ExecutorService.class);
|
||||
private static final ReportSpamTokenHandler REPORT_SPAM_TOKEN_HANDLER = mock(ReportSpamTokenHandler.class);
|
||||
|
||||
private static final ResourceExtension resources = ResourceExtension.builder()
|
||||
.addProperty(ServerProperties.UNWRAP_COMPLETION_STAGE_IN_WRITER_ENABLE, Boolean.TRUE)
|
||||
|
@ -157,7 +152,7 @@ class MessageControllerTest {
|
|||
.addResource(
|
||||
new MessageController(rateLimiters, messageSender, receiptSender, accountsManager, deletedAccountsManager,
|
||||
messagesManager, pushNotificationManager, reportMessageManager, multiRecipientMessageExecutor,
|
||||
ReportSpamTokenProvider.noop(), REPORT_SPAM_TOKEN_HANDLER))
|
||||
ReportSpamTokenProvider.noop()))
|
||||
.build();
|
||||
|
||||
@BeforeEach
|
||||
|
@ -184,8 +179,6 @@ class MessageControllerTest {
|
|||
when(accountsManager.getByAccountIdentifier(INTERNATIONAL_UUID)).thenReturn(Optional.of(internationalAccount));
|
||||
|
||||
when(rateLimiters.getMessagesLimiter()).thenReturn(rateLimiter);
|
||||
|
||||
when(REPORT_SPAM_TOKEN_HANDLER.handle(any(), any(), any(), any(), any(), any())).thenReturn(CompletableFuture.completedFuture(false));
|
||||
}
|
||||
|
||||
private static Device generateTestDevice(final long id, final int registrationId, final int pniRegistrationId, final SignedPreKey signedPreKey, final long createdAt, final long lastSeen) {
|
||||
|
@ -214,8 +207,7 @@ class MessageControllerTest {
|
|||
rateLimiter,
|
||||
pushNotificationManager,
|
||||
reportMessageManager,
|
||||
multiRecipientMessageExecutor,
|
||||
REPORT_SPAM_TOKEN_HANDLER
|
||||
multiRecipientMessageExecutor
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -720,9 +712,6 @@ class MessageControllerTest {
|
|||
when(accountsManager.getByAccountIdentifier(senderAci)).thenReturn(Optional.of(account));
|
||||
when(deletedAccountsManager.findDeletedAccountE164(senderAci)).thenReturn(Optional.of(senderNumber));
|
||||
when(accountsManager.getPhoneNumberIdentifier(senderNumber)).thenReturn(senderPni);
|
||||
when(REPORT_SPAM_TOKEN_HANDLER.handle(any(), any(), any(), any(), any(), any())).thenReturn(CompletableFuture.completedFuture(true));
|
||||
|
||||
ArgumentCaptor<byte[]> captor = ArgumentCaptor.forClass(byte[].class);
|
||||
|
||||
Entity<SpamReport> entity = Entity.entity(new SpamReport(new byte[3]), "application/json");
|
||||
Response response =
|
||||
|
@ -733,8 +722,6 @@ class MessageControllerTest {
|
|||
.post(entity);
|
||||
|
||||
assertThat(response.getStatus(), is(equalTo(202)));
|
||||
verify(REPORT_SPAM_TOKEN_HANDLER).handle(any(), any(), any(), any(), any(), captor.capture());
|
||||
assertArrayEquals(new byte[3], captor.getValue());
|
||||
verify(reportMessageManager).report(eq(Optional.of(senderNumber)),
|
||||
eq(Optional.of(senderAci)),
|
||||
eq(Optional.of(senderPni)),
|
||||
|
@ -745,8 +732,6 @@ class MessageControllerTest {
|
|||
verify(accountsManager, never()).getPhoneNumberIdentifier(anyString());
|
||||
when(accountsManager.getByAccountIdentifier(senderAci)).thenReturn(Optional.empty());
|
||||
|
||||
clearInvocations(REPORT_SPAM_TOKEN_HANDLER);
|
||||
|
||||
messageGuid = UUID.randomUUID();
|
||||
|
||||
entity = Entity.entity(new SpamReport(new byte[5]), "application/json");
|
||||
|
@ -758,8 +743,6 @@ class MessageControllerTest {
|
|||
.post(entity);
|
||||
|
||||
assertThat(response.getStatus(), is(equalTo(202)));
|
||||
verify(REPORT_SPAM_TOKEN_HANDLER).handle(any(), any(), any(), any(), any(), captor.capture());
|
||||
assertArrayEquals(new byte[5], captor.getValue());
|
||||
verify(reportMessageManager).report(eq(Optional.of(senderNumber)),
|
||||
eq(Optional.of(senderAci)),
|
||||
eq(Optional.of(senderPni)),
|
||||
|
|
Loading…
Reference in New Issue