Clarify naming around spam filtering.

This commit is contained in:
erik-signal 2023-01-27 11:40:33 -05:00 committed by GitHub
parent a01fcdad28
commit a89e30fe75
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 54 additions and 78 deletions

2
.gitmodules vendored
View File

@ -7,5 +7,5 @@
#
# External developers may safely ignore this submodule.
[submodule "abusive-message-filter"]
path = abusive-message-filter
path = spam-filter
url = REDACTED

10
pom.xml
View File

@ -364,22 +364,22 @@
<profiles>
<profile>
<id>include-abusive-message-filter</id>
<id>include-spam-filter</id>
<activation>
<file>
<exists>abusive-message-filter/pom.xml</exists>
<exists>spam-filter/pom.xml</exists>
</file>
</activation>
<modules>
<module>abusive-message-filter</module>
<module>spam-filter</module>
</modules>
</profile>
<profile>
<id>exclude-abusive-message-filter</id>
<id>exclude-spam-filter</id>
<activation>
<file>
<missing>abusive-message-filter/pom.xml</missing>
<missing>spam-filter/pom.xml</missing>
</file>
</activation>
</profile>

View File

@ -446,7 +446,7 @@
<profiles>
<profile>
<id>exclude-abusive-message-filter</id>
<id>exclude-spam-filter</id>
<build>
<plugins>
<plugin>

View File

@ -12,7 +12,7 @@ import java.util.List;
import java.util.Map;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import org.whispersystems.textsecuregcm.configuration.AbusiveMessageFilterConfiguration;
import org.whispersystems.textsecuregcm.configuration.SpamFilterConfiguration;
import org.whispersystems.textsecuregcm.configuration.AccountDatabaseCrawlerConfiguration;
import org.whispersystems.textsecuregcm.configuration.AdminEventLoggingConfiguration;
import org.whispersystems.textsecuregcm.configuration.ApnConfiguration;
@ -268,7 +268,7 @@ public class WhisperServerConfiguration extends Configuration {
@Valid
@JsonProperty
private AbusiveMessageFilterConfiguration abusiveMessageFilter;
private SpamFilterConfiguration spamFilterConfiguration;
@Valid
@NotNull
@ -453,8 +453,8 @@ public class WhisperServerConfiguration extends Configuration {
return reportMessage;
}
public AbusiveMessageFilterConfiguration getAbusiveMessageFilterConfiguration() {
return abusiveMessageFilter;
public SpamFilterConfiguration getSpamFilterConfiguration() {
return spamFilterConfiguration;
}
public UsernameConfiguration getUsername() {

View File

@ -70,11 +70,11 @@ import org.signal.libsignal.zkgroup.receipts.ServerZkReceiptOperations;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.dispatch.DispatchManager;
import org.whispersystems.textsecuregcm.abuse.AbusiveMessageFilter;
import org.whispersystems.textsecuregcm.abuse.FilterAbusiveMessages;
import org.whispersystems.textsecuregcm.abuse.RateLimitChallengeListener;
import org.whispersystems.textsecuregcm.abuse.ReportSpamTokenHandler;
import org.whispersystems.textsecuregcm.abuse.ReportSpamTokenProvider;
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;
@ -677,14 +677,14 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
environment.jersey().register(new KeysController(rateLimiters, keys, accountsManager));
boolean registeredAbusiveMessageFilter = false;
boolean registeredSpamFilter = false;
ReportSpamTokenProvider reportSpamTokenProvider = null;
ReportSpamTokenHandler reportSpamTokenHandler = null;
for (final AbusiveMessageFilter filter : ServiceLoader.load(AbusiveMessageFilter.class)) {
if (filter.getClass().isAnnotationPresent(FilterAbusiveMessages.class)) {
for (final SpamFilter filter : ServiceLoader.load(SpamFilter.class)) {
if (filter.getClass().isAnnotationPresent(FilterSpam.class)) {
try {
filter.configure(config.getAbusiveMessageFilterConfiguration().getEnvironment());
filter.configure(config.getSpamFilterConfiguration().getEnvironment());
ReportSpamTokenProvider thisProvider = filter.getReportSpamTokenProvider();
if (reportSpamTokenProvider == null) {
@ -704,13 +704,13 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
environment.jersey().register(filter);
webSocketEnvironment.jersey().register(filter);
log.info("Registered abusive message filter: {}", filter.getClass().getName());
registeredAbusiveMessageFilter = true;
log.info("Registered spam filter: {}", filter.getClass().getName());
registeredSpamFilter = true;
} catch (final Exception e) {
log.warn("Failed to register abusive message filter: {}", filter.getClass().getName(), e);
log.warn("Failed to register spam filter: {}", filter.getClass().getName(), e);
}
} else {
log.warn("Abusive message filter {} not annotated with @FilterAbusiveMessages and will not be installed",
log.warn("Spam filter {} not annotated with @FilterSpam and will not be installed",
filter.getClass().getName());
}
@ -720,8 +720,8 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
}
}
if (!registeredAbusiveMessageFilter) {
log.warn("No abusive message filters installed");
if (!registeredSpamFilter) {
log.warn("No spam filters installed");
}
if (reportSpamTokenProvider == null) {

View File

@ -9,14 +9,14 @@ import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import javax.validation.constraints.NotBlank;
public class AbusiveMessageFilterConfiguration {
public class SpamFilterConfiguration {
@JsonProperty
@NotBlank
private final String environment;
@JsonCreator
public AbusiveMessageFilterConfiguration(@JsonProperty("environment") final String environment) {
public SpamFilterConfiguration(@JsonProperty("environment") final String environment) {
this.environment = environment;
}

View File

@ -1,14 +0,0 @@
package org.whispersystems.textsecuregcm.configuration.dynamic;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.time.Duration;
public class DynamicAbusiveHostRulesConfiguration {
@JsonProperty
private Duration expirationTime = Duration.ofDays(1);
public Duration getExpirationTime() {
return expirationTime;
}
}

View File

@ -1,7 +1,6 @@
package org.whispersystems.textsecuregcm.configuration.dynamic;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.annotations.VisibleForTesting;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
@ -48,10 +47,6 @@ public class DynamicConfiguration {
@Valid
private DynamicTurnConfiguration turn = new DynamicTurnConfiguration();
@JsonProperty
@Valid
DynamicAbusiveHostRulesConfiguration abusiveHostRules = new DynamicAbusiveHostRulesConfiguration();
@JsonProperty
@Valid
DynamicMessagePersisterConfiguration messagePersister = new DynamicMessagePersisterConfiguration();
@ -102,10 +97,6 @@ public class DynamicConfiguration {
return turn;
}
public DynamicAbusiveHostRulesConfiguration getAbusiveHostRules() {
return abusiveHostRules;
}
public DynamicMessagePersisterConfiguration getMessagePersisterConfiguration() {
return messagePersister;
}

View File

@ -55,7 +55,7 @@ import javax.ws.rs.core.Response.Status;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.abuse.FilterAbusiveMessages;
import org.whispersystems.textsecuregcm.spam.FilterSpam;
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials;
import org.whispersystems.textsecuregcm.auth.BasicAuthorizationHeader;
@ -265,7 +265,7 @@ public class AccountController {
@Timed
@GET
@Path("/{transport}/code/{number}")
@FilterAbusiveMessages
@FilterSpam
@Produces(MediaType.APPLICATION_JSON)
public Response createAccount(@PathParam("transport") String transport,
@PathParam("number") String number,

View File

@ -62,9 +62,9 @@ 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.abuse.FilterAbusiveMessages;
import org.whispersystems.textsecuregcm.abuse.ReportSpamTokenHandler;
import org.whispersystems.textsecuregcm.abuse.ReportSpamTokenProvider;
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;
@ -177,7 +177,7 @@ public class MessageController {
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@FilterAbusiveMessages
@FilterSpam
public Response sendMessage(@Auth Optional<AuthenticatedAccount> source,
@HeaderParam(OptionalAccess.UNIDENTIFIED) Optional<Anonymous> accessKey,
@HeaderParam(HttpHeaders.USER_AGENT) String userAgent,
@ -355,7 +355,7 @@ public class MessageController {
@PUT
@Consumes(MultiRecipientMessageProvider.MEDIA_TYPE)
@Produces(MediaType.APPLICATION_JSON)
@FilterAbusiveMessages
@FilterSpam
public Response sendMultiRecipientMessage(
@HeaderParam(OptionalAccess.UNIDENTIFIED) @Nullable CombinedUnidentifiedSenderAccessKeys accessKeys,
@HeaderParam(HttpHeaders.USER_AGENT) String userAgent,

View File

@ -9,7 +9,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.whispersystems.textsecuregcm.abuse.RateLimitChallengeListener;
import org.whispersystems.textsecuregcm.spam.RateLimitChallengeListener;
import org.whispersystems.textsecuregcm.captcha.CaptchaChecker;
import org.whispersystems.textsecuregcm.controllers.RateLimitExceededException;
import org.whispersystems.textsecuregcm.metrics.UserAgentTagUtil;

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.abuse;
package org.whispersystems.textsecuregcm.spam;
import javax.ws.rs.NameBinding;
import java.lang.annotation.ElementType;
@ -12,10 +12,10 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* A name-binding annotation that associates {@link AbusiveMessageFilter}s with resource methods.
* A name-binding annotation that associates {@link SpamFilter}s with resource methods.
*/
@NameBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface FilterAbusiveMessages {
public @interface FilterSpam {
}

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.abuse;
package org.whispersystems.textsecuregcm.spam;
import org.whispersystems.textsecuregcm.storage.Account;

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.abuse;
package org.whispersystems.textsecuregcm.spam;
public enum RateLimitChallengeType {

View File

@ -1,4 +1,4 @@
package org.whispersystems.textsecuregcm.abuse;
package org.whispersystems.textsecuregcm.spam;
import java.util.Optional;
import java.util.UUID;

View File

@ -1,4 +1,4 @@
package org.whispersystems.textsecuregcm.abuse;
package org.whispersystems.textsecuregcm.spam;
import javax.ws.rs.container.ContainerRequestContext;
import java.util.Optional;

View File

@ -3,27 +3,27 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.abuse;
package org.whispersystems.textsecuregcm.spam;
import io.dropwizard.lifecycle.Managed;
import javax.ws.rs.container.ContainerRequestFilter;
import java.io.IOException;
/**
* An abusive message filter is a {@link ContainerRequestFilter} that filters requests to message-sending endpoints to
* detect and respond to patterns of abusive behavior.
* A spam filter is a {@link ContainerRequestFilter} that filters requests to message-sending endpoints to
* detect and respond to patterns of spam.
* <p/>
* Abusive message filters are managed components that are generally loaded dynamically via a
* Spam filters are managed components that are generally loaded dynamically via a
* {@link java.util.ServiceLoader}. Their {@link #configure(String)} method will be called prior to be adding to the
* server's pool of {@link Managed} objects.
* <p/>
* Abusive message filters must be annotated with {@link FilterAbusiveMessages}, a name binding annotation that
* Spam filters must be annotated with {@link FilterSpam}, a name binding annotation that
* restricts the endpoints to which the filter may apply.
*/
public interface AbusiveMessageFilter extends ContainerRequestFilter, Managed {
public interface SpamFilter extends ContainerRequestFilter, Managed {
/**
* Configures this abusive message filter. This method will be called before the filter is added to the server's pool
* Configures this spam filter. This method will be called before the filter is added to the server's pool
* of managed objects and before the server processes any requests.
*
* @param environmentName the name of the environment in which this filter is running (e.g. "staging" or "production")

View File

@ -89,7 +89,7 @@ public class ReportMessageManager {
}
/**
* Returns the number of times messages from the given account have been reported by recipients as abusive. Note that
* Returns the number of times messages from the given account have been reported by recipients as spam. Note that
* this method makes a call to an external service, and callers should take care to memoize calls where possible and
* avoid unnecessary calls.
*

View File

@ -67,8 +67,8 @@ 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.whispersystems.textsecuregcm.abuse.ReportSpamTokenHandler;
import org.whispersystems.textsecuregcm.abuse.ReportSpamTokenProvider;
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;

View File

@ -12,11 +12,10 @@ import java.util.UUID;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.whispersystems.textsecuregcm.abuse.RateLimitChallengeListener;
import org.whispersystems.textsecuregcm.spam.RateLimitChallengeListener;
import org.whispersystems.textsecuregcm.captcha.AssessmentResult;
import org.whispersystems.textsecuregcm.captcha.CaptchaChecker;
import org.whispersystems.textsecuregcm.controllers.RateLimitExceededException;
import org.whispersystems.textsecuregcm.captcha.RecaptchaClient;
import org.whispersystems.textsecuregcm.storage.Account;
class RateLimitChallengeManagerTest {