Remove transitional and legacy client

This commit is contained in:
Chris Eager 2022-03-03 17:40:15 -08:00 committed by Chris Eager
parent a984b3640e
commit 2a68d9095d
9 changed files with 23 additions and 223 deletions

View File

@ -242,9 +242,6 @@ voiceVerification:
locales:
- en
recaptcha:
secret: unset
recaptchaV2:
projectPath: projects/example
credentialConfigurationJson: "{ }" # service account configuration for backend authentication

View File

@ -35,7 +35,6 @@ import org.whispersystems.textsecuregcm.configuration.MessageCacheConfiguration;
import org.whispersystems.textsecuregcm.configuration.PaymentsServiceConfiguration;
import org.whispersystems.textsecuregcm.configuration.PushConfiguration;
import org.whispersystems.textsecuregcm.configuration.RateLimitsConfiguration;
import org.whispersystems.textsecuregcm.configuration.RecaptchaConfiguration;
import org.whispersystems.textsecuregcm.configuration.RecaptchaV2Configuration;
import org.whispersystems.textsecuregcm.configuration.RedisClusterConfiguration;
import org.whispersystems.textsecuregcm.configuration.RedisConfiguration;
@ -206,11 +205,6 @@ public class WhisperServerConfiguration extends Configuration {
@JsonProperty
private VoiceVerificationConfiguration voiceVerification;
@Valid
@NotNull
@JsonProperty
private RecaptchaConfiguration recaptcha;
@Valid
@NotNull
@JsonProperty
@ -289,10 +283,6 @@ public class WhisperServerConfiguration extends Configuration {
return dynamoDbTables;
}
public RecaptchaConfiguration getRecaptchaConfiguration() {
return recaptcha;
}
public RecaptchaV2Configuration getRecaptchaV2Configuration() {
return recaptchaV2;
}

View File

@ -151,8 +151,6 @@ import org.whispersystems.textsecuregcm.push.MessageSender;
import org.whispersystems.textsecuregcm.push.ProvisioningManager;
import org.whispersystems.textsecuregcm.push.ReceiptSender;
import org.whispersystems.textsecuregcm.recaptcha.EnterpriseRecaptchaClient;
import org.whispersystems.textsecuregcm.recaptcha.LegacyRecaptchaClient;
import org.whispersystems.textsecuregcm.recaptcha.TransitionalRecaptchaClient;
import org.whispersystems.textsecuregcm.redis.ConnectionEventLogger;
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster;
import org.whispersystems.textsecuregcm.redis.ReplicatedJedisPool;
@ -474,16 +472,13 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
MessageSender messageSender = new MessageSender(apnFallbackManager, clientPresenceManager, messagesManager, gcmSender, apnSender, pushLatencyManager);
ReceiptSender receiptSender = new ReceiptSender(accountsManager, messageSender);
TurnTokenGenerator turnTokenGenerator = new TurnTokenGenerator(config.getTurnConfiguration());
LegacyRecaptchaClient legacyRecaptchaClient = new LegacyRecaptchaClient(config.getRecaptchaConfiguration().getSecret());
EnterpriseRecaptchaClient enterpriseRecaptchaClient = new EnterpriseRecaptchaClient(
config.getRecaptchaV2Configuration().getProjectPath(),
config.getRecaptchaV2Configuration().getCredentialConfigurationJson(),
dynamicConfigurationManager);
TransitionalRecaptchaClient transitionalRecaptchaClient = new TransitionalRecaptchaClient(legacyRecaptchaClient,
enterpriseRecaptchaClient);
PushChallengeManager pushChallengeManager = new PushChallengeManager(apnSender, gcmSender, pushChallengeDynamoDb);
RateLimitChallengeManager rateLimitChallengeManager = new RateLimitChallengeManager(pushChallengeManager,
transitionalRecaptchaClient, dynamicRateLimiters);
enterpriseRecaptchaClient, dynamicRateLimiters);
RateLimitChallengeOptionManager rateLimitChallengeOptionManager =
new RateLimitChallengeOptionManager(dynamicRateLimiters, dynamicConfigurationManager);
@ -620,7 +615,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
environment.jersey().register(
new AccountController(pendingAccountsManager, accountsManager, abusiveHostRules, rateLimiters,
smsSender, dynamicConfigurationManager, turnTokenGenerator, config.getTestDevices(),
transitionalRecaptchaClient, gcmSender, apnSender, backupCredentialsGenerator,
enterpriseRecaptchaClient, gcmSender, apnSender, backupCredentialsGenerator,
verifyExperimentEnrollmentManager));
environment.jersey().register(new KeysController(rateLimiters, keys, accountsManager));

View File

@ -1,21 +0,0 @@
/*
* Copyright 2013-2020 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import javax.validation.constraints.NotEmpty;
public class RecaptchaConfiguration {
@JsonProperty
@NotEmpty
private String secret;
public String getSecret() {
return secret;
}
}

View File

@ -22,6 +22,7 @@ import java.nio.charset.StandardCharsets;
import java.util.Objects;
import javax.annotation.Nonnull;
import javax.ws.rs.BadRequestException;
import org.apache.commons.lang3.StringUtils;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
@ -29,6 +30,8 @@ public class EnterpriseRecaptchaClient implements RecaptchaClient {
@VisibleForTesting
static final String SEPARATOR = ".";
@VisibleForTesting
static final String V2_PREFIX = "signal-recaptcha-v2" + EnterpriseRecaptchaClient.SEPARATOR;
private static final String ASSESSMENTS_COUNTER_NAME = name(EnterpriseRecaptchaClient.class, "assessments");
private static final String SCORE_DISTRIBUTION_NAME = name(EnterpriseRecaptchaClient.class, "scoreDistribution");
@ -61,7 +64,7 @@ public class EnterpriseRecaptchaClient implements RecaptchaClient {
* dont need to be strict.
*/
static String[] parseInputToken(final String input) {
String[] keyActionAndToken = input.split("\\" + SEPARATOR, 3);
String[] keyActionAndToken = StringUtils.removeStart(input, V2_PREFIX).split("\\" + SEPARATOR, 3);
if (keyActionAndToken.length == 1) {
throw new BadRequestException("too few parts");

View File

@ -1,70 +0,0 @@
/*
* Copyright 2013-2020 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.recaptcha;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
import org.glassfish.jersey.client.ClientConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
public class LegacyRecaptchaClient implements RecaptchaClient {
private final Logger logger = LoggerFactory.getLogger(LegacyRecaptchaClient.class);
private final Client client;
private final String recaptchaSecret;
public LegacyRecaptchaClient(String recaptchaSecret) {
this.client = ClientBuilder.newClient(new ClientConfig(new JacksonJaxbJsonProvider().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)));
this.recaptchaSecret = recaptchaSecret;
}
public boolean verify(String captchaToken, String ip) {
MultivaluedMap<String, String> formData = new MultivaluedHashMap<>();
formData.add("secret", recaptchaSecret);
formData.add("response", captchaToken);
formData.add("remoteip", ip);
VerifyResponse response = client.target("https://www.google.com/recaptcha/api/siteverify")
.request()
.post(Entity.form(formData), VerifyResponse.class);
if (response.success) {
logger.debug("Got successful captcha time: " + response.challenge_ts + ", current time: " + System.currentTimeMillis());
}
return response.success;
}
private static class VerifyResponse {
@JsonProperty
private boolean success;
@JsonProperty("error-codes")
private String[] errorCodes;
@JsonProperty
private String hostname;
@JsonProperty
private String challenge_ts;
@Override
public String toString() {
return "success: " + success + ", errorCodes: " + String.join(", ", errorCodes == null ? new String[0] : errorCodes) + ", hostname: " + hostname + ", challenge_ts: " + challenge_ts;
}
}
}

View File

@ -1,36 +0,0 @@
/*
* Copyright 2021-2022 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.recaptcha;
import com.google.common.annotations.VisibleForTesting;
import java.util.Objects;
import javax.annotation.Nonnull;
public class TransitionalRecaptchaClient implements RecaptchaClient {
@VisibleForTesting
static final String V2_PREFIX = "signal-recaptcha-v2" + EnterpriseRecaptchaClient.SEPARATOR;
private final LegacyRecaptchaClient legacyRecaptchaClient;
private final EnterpriseRecaptchaClient enterpriseRecaptchaClient;
public TransitionalRecaptchaClient(
@Nonnull final LegacyRecaptchaClient legacyRecaptchaClient,
@Nonnull final EnterpriseRecaptchaClient enterpriseRecaptchaClient) {
this.legacyRecaptchaClient = Objects.requireNonNull(legacyRecaptchaClient);
this.enterpriseRecaptchaClient = Objects.requireNonNull(enterpriseRecaptchaClient);
}
@Override
public boolean verify(@Nonnull final String token, @Nonnull final String ip) {
if (token.startsWith(V2_PREFIX)) {
return enterpriseRecaptchaClient.verify(token.substring(V2_PREFIX.length()), ip);
} else {
return legacyRecaptchaClient.verify(token, ip);
}
}
}

View File

@ -19,6 +19,8 @@ import org.junit.jupiter.params.provider.MethodSource;
class EnterpriseRecaptchaClientTest {
private static final String PREFIX = EnterpriseRecaptchaClient.V2_PREFIX.substring(0,
EnterpriseRecaptchaClient.V2_PREFIX.lastIndexOf(SEPARATOR));
private static final String SITE_KEY = "site-key";
private static final String TOKEN = "some-token";
@ -57,6 +59,21 @@ class EnterpriseRecaptchaClientTest {
String.join(SEPARATOR, SITE_KEY, "an-action", TOKEN, "something-else"),
TOKEN + SEPARATOR + "something-else",
SITE_KEY,
"an-action"),
Arguments.of(
String.join(SEPARATOR, PREFIX, SITE_KEY, TOKEN),
TOKEN,
SITE_KEY,
null),
Arguments.of(
String.join(SEPARATOR, PREFIX, SITE_KEY, "an-action", TOKEN),
TOKEN,
SITE_KEY,
"an-action"),
Arguments.of(
String.join(SEPARATOR, PREFIX, SITE_KEY, "an-action", TOKEN, "something-else"),
TOKEN + SEPARATOR + "something-else",
SITE_KEY,
"an-action")
);
}

View File

@ -1,75 +0,0 @@
/*
* Copyright 2022 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.recaptcha;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.whispersystems.textsecuregcm.recaptcha.EnterpriseRecaptchaClient.SEPARATOR;
import java.util.stream.Stream;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
class TransitionalRecaptchaClientTest {
private TransitionalRecaptchaClient transitionalRecaptchaClient;
private EnterpriseRecaptchaClient enterpriseRecaptchaClient;
private LegacyRecaptchaClient legacyRecaptchaClient;
private static final String PREFIX = TransitionalRecaptchaClient.V2_PREFIX.substring(0,
TransitionalRecaptchaClient.V2_PREFIX.lastIndexOf(SEPARATOR));
private static final String TOKEN = "some-token";
private static final String IP_ADDRESS = "127.0.0.1";
@BeforeEach
void setup() {
enterpriseRecaptchaClient = mock(EnterpriseRecaptchaClient.class);
legacyRecaptchaClient = mock(LegacyRecaptchaClient.class);
transitionalRecaptchaClient = new TransitionalRecaptchaClient(legacyRecaptchaClient, enterpriseRecaptchaClient);
}
@ParameterizedTest
@MethodSource
void testVerify(final String inputToken, final boolean expectLegacy, final String expectedToken) {
transitionalRecaptchaClient.verify(inputToken, IP_ADDRESS);
if (expectLegacy) {
verifyNoInteractions(enterpriseRecaptchaClient);
verify(legacyRecaptchaClient).verify(expectedToken, IP_ADDRESS);
} else {
verifyNoInteractions(legacyRecaptchaClient);
verify(enterpriseRecaptchaClient).verify(expectedToken, IP_ADDRESS);
}
}
static Stream<Arguments> testVerify() {
return Stream.of(
Arguments.of(
TOKEN,
true,
TOKEN),
Arguments.of(
String.join(SEPARATOR, PREFIX, TOKEN),
false,
TOKEN),
Arguments.of(
String.join(SEPARATOR, PREFIX, "site-key", "an-action", TOKEN),
false,
String.join(SEPARATOR, "site-key", "an-action", TOKEN),
"an-action"),
Arguments.of(
String.join(SEPARATOR, PREFIX, "site-key", "an-action", TOKEN, "something-else"),
false,
"site-key" + SEPARATOR + "an-action" + SEPARATOR + TOKEN + SEPARATOR + "something-else")
);
}
}