mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-21 19:28:05 +01:00
Add a captcha short-code expander
This commit is contained in:
committed by
ravi-signal
parent
1dde612855
commit
3ac7aba6b2
@@ -50,6 +50,7 @@ import org.whispersystems.textsecuregcm.configuration.ReportMessageConfiguration
|
||||
import org.whispersystems.textsecuregcm.configuration.SecureBackupServiceConfiguration;
|
||||
import org.whispersystems.textsecuregcm.configuration.SecureStorageServiceConfiguration;
|
||||
import org.whispersystems.textsecuregcm.configuration.SecureValueRecovery2Configuration;
|
||||
import org.whispersystems.textsecuregcm.configuration.ShortCodeExpanderConfiguration;
|
||||
import org.whispersystems.textsecuregcm.configuration.SpamFilterConfiguration;
|
||||
import org.whispersystems.textsecuregcm.configuration.StripeConfiguration;
|
||||
import org.whispersystems.textsecuregcm.configuration.SubscriptionConfiguration;
|
||||
@@ -202,6 +203,11 @@ public class WhisperServerConfiguration extends Configuration {
|
||||
@JsonProperty
|
||||
private HCaptchaConfiguration hCaptcha;
|
||||
|
||||
@Valid
|
||||
@NotNull
|
||||
@JsonProperty
|
||||
private ShortCodeExpanderConfiguration shortCode;
|
||||
|
||||
@Valid
|
||||
@NotNull
|
||||
@JsonProperty
|
||||
@@ -334,6 +340,10 @@ public class WhisperServerConfiguration extends Configuration {
|
||||
return hCaptcha;
|
||||
}
|
||||
|
||||
public ShortCodeExpanderConfiguration getShortCodeRetrieverConfiguration() {
|
||||
return shortCode;
|
||||
}
|
||||
|
||||
public WebSocketConfiguration getWebSocketConfiguration() {
|
||||
return webSocket;
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ import org.whispersystems.textsecuregcm.captcha.CaptchaChecker;
|
||||
import org.whispersystems.textsecuregcm.captcha.HCaptchaClient;
|
||||
import org.whispersystems.textsecuregcm.captcha.RecaptchaClient;
|
||||
import org.whispersystems.textsecuregcm.captcha.RegistrationCaptchaManager;
|
||||
import org.whispersystems.textsecuregcm.captcha.ShortCodeExpander;
|
||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
||||
import org.whispersystems.textsecuregcm.configuration.secrets.SecretStore;
|
||||
import org.whispersystems.textsecuregcm.configuration.secrets.SecretsModule;
|
||||
@@ -581,7 +582,10 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
||||
.connectTimeout(Duration.ofSeconds(10)).build();
|
||||
HCaptchaClient hCaptchaClient = new HCaptchaClient(config.getHCaptchaConfiguration().apiKey().value(), hcaptchaHttpClient,
|
||||
dynamicConfigurationManager);
|
||||
CaptchaChecker captchaChecker = new CaptchaChecker(List.of(recaptchaClient, hCaptchaClient));
|
||||
HttpClient shortCodeRetrieverHttpClient = HttpClient.newBuilder().version(HttpClient.Version.HTTP_2)
|
||||
.connectTimeout(Duration.ofSeconds(10)).build();
|
||||
ShortCodeExpander shortCodeRetriever = new ShortCodeExpander(shortCodeRetrieverHttpClient, config.getShortCodeRetrieverConfiguration().baseUrl());
|
||||
CaptchaChecker captchaChecker = new CaptchaChecker(shortCodeRetriever, List.of(recaptchaClient, hCaptchaClient));
|
||||
|
||||
PushChallengeManager pushChallengeManager = new PushChallengeManager(pushNotificationManager,
|
||||
pushChallengeDynamoDb);
|
||||
|
||||
@@ -29,9 +29,15 @@ public class CaptchaChecker {
|
||||
@VisibleForTesting
|
||||
static final String SEPARATOR = ".";
|
||||
|
||||
private static final String SHORT_SUFFIX = "-short";
|
||||
|
||||
private final ShortCodeExpander shortCodeExpander;
|
||||
private final Map<String, CaptchaClient> captchaClientMap;
|
||||
|
||||
public CaptchaChecker(final List<CaptchaClient> captchaClients) {
|
||||
public CaptchaChecker(
|
||||
final ShortCodeExpander shortCodeRetriever,
|
||||
final List<CaptchaClient> captchaClients) {
|
||||
this.shortCodeExpander = shortCodeRetriever;
|
||||
this.captchaClientMap = captchaClients.stream()
|
||||
.collect(Collectors.toMap(CaptchaClient::scheme, Function.identity()));
|
||||
}
|
||||
@@ -63,9 +69,17 @@ public class CaptchaChecker {
|
||||
final String prefix = parts[0];
|
||||
final String siteKey = parts[1].toLowerCase(Locale.ROOT).strip();
|
||||
final String action = parts[2];
|
||||
final String token = parts[3];
|
||||
String token = parts[3];
|
||||
|
||||
final CaptchaClient client = this.captchaClientMap.get(prefix);
|
||||
String provider = prefix;
|
||||
if (prefix.endsWith(SHORT_SUFFIX)) {
|
||||
// This is a "short" solution that points to the actual solution. We need to fetch the
|
||||
// full solution before proceeding
|
||||
provider = prefix.substring(0, prefix.length() - SHORT_SUFFIX.length());
|
||||
token = shortCodeExpander.retrieve(token).orElseThrow(() -> new BadRequestException("invalid shortcode"));
|
||||
}
|
||||
|
||||
final CaptchaClient client = this.captchaClientMap.get(provider);
|
||||
if (client == null) {
|
||||
throw new BadRequestException("invalid captcha scheme");
|
||||
}
|
||||
@@ -92,7 +106,7 @@ public class CaptchaChecker {
|
||||
Metrics.counter(ASSESSMENTS_COUNTER_NAME,
|
||||
"action", action,
|
||||
"score", result.getScoreString(),
|
||||
"provider", prefix)
|
||||
"provider", provider)
|
||||
.increment();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.captcha;
|
||||
|
||||
import io.micrometer.core.instrument.Metrics;
|
||||
import org.apache.http.HttpStatus;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.whispersystems.textsecuregcm.metrics.MetricsUtil.name;
|
||||
|
||||
public class ShortCodeExpander {
|
||||
private static final String EXPAND_COUNTER_NAME = name(ShortCodeExpander.class, "expand");
|
||||
|
||||
private final HttpClient client;
|
||||
private final URI shortenerHost;
|
||||
|
||||
public ShortCodeExpander(final HttpClient client, final String shortenerHost) {
|
||||
this.client = client;
|
||||
this.shortenerHost = URI.create(shortenerHost);
|
||||
}
|
||||
|
||||
public Optional<String> retrieve(final String shortCode) throws IOException {
|
||||
final URI uri = shortenerHost.resolve("/" + shortCode);
|
||||
final HttpRequest request = HttpRequest.newBuilder().uri(uri).GET().build();
|
||||
|
||||
try {
|
||||
final HttpResponse<String> response = this.client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
Metrics.counter(EXPAND_COUNTER_NAME, "responseCode", Integer.toString(response.statusCode())).increment();
|
||||
return switch (response.statusCode()) {
|
||||
case HttpStatus.SC_OK -> Optional.of(response.body());
|
||||
case HttpStatus.SC_NOT_FOUND -> Optional.empty();
|
||||
default -> throw new IOException("Failed to look up shortcode");
|
||||
};
|
||||
} catch (InterruptedException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.configuration;
|
||||
|
||||
public record ShortCodeExpanderConfiguration(String baseUrl) {
|
||||
}
|
||||
Reference in New Issue
Block a user