mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-20 17:38:04 +01:00
Add client challenges for prekey and message rate limiters
This commit is contained in:
@@ -15,6 +15,7 @@ import io.lettuce.core.ScriptOutputType;
|
||||
import io.lettuce.core.cluster.SlotHash;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.whispersystems.textsecuregcm.push.ApnMessage.Type;
|
||||
import org.whispersystems.textsecuregcm.redis.ClusterLuaScript;
|
||||
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster;
|
||||
import org.whispersystems.textsecuregcm.redis.RedisException;
|
||||
@@ -192,7 +193,7 @@ public class ApnFallbackManager implements Managed {
|
||||
return;
|
||||
}
|
||||
|
||||
apnSender.sendMessage(new ApnMessage(apnId, account.getNumber(), device.getId(), true, Optional.empty()));
|
||||
apnSender.sendMessage(new ApnMessage(apnId, account.getNumber(), device.getId(), true, Type.NOTIFICATION, Optional.empty()));
|
||||
retry.mark();
|
||||
}
|
||||
|
||||
|
||||
@@ -12,21 +12,28 @@ import java.util.Optional;
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
public class ApnMessage {
|
||||
|
||||
public static final String APN_NOTIFICATION_PAYLOAD = "{\"aps\":{\"sound\":\"default\",\"alert\":{\"loc-key\":\"APN_Message\"}}}";
|
||||
public static final String APN_CHALLENGE_PAYLOAD = "{\"aps\":{\"sound\":\"default\",\"alert\":{\"loc-key\":\"APN_Message\"}}, \"challenge\" : \"%s\"}";
|
||||
public static final long MAX_EXPIRATION = Integer.MAX_VALUE * 1000L;
|
||||
public enum Type {
|
||||
NOTIFICATION, CHALLENGE, RATE_LIMIT_CHALLENGE
|
||||
}
|
||||
|
||||
public static final String APN_NOTIFICATION_PAYLOAD = "{\"aps\":{\"sound\":\"default\",\"alert\":{\"loc-key\":\"APN_Message\"}}}";
|
||||
public static final String APN_CHALLENGE_PAYLOAD = "{\"aps\":{\"sound\":\"default\",\"alert\":{\"loc-key\":\"APN_Message\"}}, \"challenge\" : \"%s\"}";
|
||||
public static final String APN_RATE_LIMIT_CHALLENGE_PAYLOAD = "{\"aps\":{\"sound\":\"default\",\"alert\":{\"loc-key\":\"APN_Message\"}}, \"rateLimitChallenge\" : \"%s\"}";
|
||||
public static final long MAX_EXPIRATION = Integer.MAX_VALUE * 1000L;
|
||||
|
||||
private final String apnId;
|
||||
private final String number;
|
||||
private final long deviceId;
|
||||
private final boolean isVoip;
|
||||
private final Type type;
|
||||
private final Optional<String> challengeData;
|
||||
|
||||
public ApnMessage(String apnId, String number, long deviceId, boolean isVoip, Optional<String> challengeData) {
|
||||
this.apnId = apnId;
|
||||
this.number = number;
|
||||
this.deviceId = deviceId;
|
||||
this.isVoip = isVoip;
|
||||
public ApnMessage(String apnId, String number, long deviceId, boolean isVoip, Type type, Optional<String> challengeData) {
|
||||
this.apnId = apnId;
|
||||
this.number = number;
|
||||
this.deviceId = deviceId;
|
||||
this.isVoip = isVoip;
|
||||
this.type = type;
|
||||
this.challengeData = challengeData;
|
||||
}
|
||||
|
||||
@@ -39,8 +46,19 @@ public class ApnMessage {
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
if (!challengeData.isPresent()) return APN_NOTIFICATION_PAYLOAD;
|
||||
else return String.format(APN_CHALLENGE_PAYLOAD, challengeData.get());
|
||||
switch (type) {
|
||||
case NOTIFICATION:
|
||||
return APN_NOTIFICATION_PAYLOAD;
|
||||
|
||||
case CHALLENGE:
|
||||
return String.format(APN_CHALLENGE_PAYLOAD, challengeData.orElseThrow(AssertionError::new));
|
||||
|
||||
case RATE_LIMIT_CHALLENGE:
|
||||
return String.format(APN_RATE_LIMIT_CHALLENGE_PAYLOAD, challengeData.orElseThrow(AssertionError::new));
|
||||
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
||||
@@ -5,10 +5,18 @@
|
||||
|
||||
package org.whispersystems.textsecuregcm.push;
|
||||
|
||||
import static com.codahale.metrics.MetricRegistry.name;
|
||||
|
||||
import com.codahale.metrics.Meter;
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import com.codahale.metrics.SharedMetricRegistries;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.whispersystems.gcm.server.Message;
|
||||
@@ -22,15 +30,6 @@ import org.whispersystems.textsecuregcm.util.Constants;
|
||||
import org.whispersystems.textsecuregcm.util.SystemMapper;
|
||||
import org.whispersystems.textsecuregcm.util.Util;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.codahale.metrics.MetricRegistry.name;
|
||||
|
||||
public class GCMSender {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(GCMSender.class);
|
||||
@@ -45,6 +44,7 @@ public class GCMSender {
|
||||
put("receipt", metricRegistry.meter(name(getClass(), "outbound", "receipt")));
|
||||
put("notification", metricRegistry.meter(name(getClass(), "outbound", "notification")));
|
||||
put("challenge", metricRegistry.meter(name(getClass(), "outbound", "challenge")));
|
||||
put("rateLimitChallenge", metricRegistry.meter(name(getClass(), "outbound", "rateLimitChallenge")));
|
||||
}};
|
||||
|
||||
private final AccountsManager accountsManager;
|
||||
@@ -72,9 +72,10 @@ public class GCMSender {
|
||||
String key;
|
||||
|
||||
switch (message.getType()) {
|
||||
case NOTIFICATION: key = "notification"; break;
|
||||
case CHALLENGE: key = "challenge"; break;
|
||||
default: throw new AssertionError();
|
||||
case NOTIFICATION: key = "notification"; break;
|
||||
case CHALLENGE: key = "challenge"; break;
|
||||
case RATE_LIMIT_CHALLENGE: key = "rateLimitChallenge"; break;
|
||||
default: throw new AssertionError();
|
||||
}
|
||||
|
||||
Message request = builder.withDataPart(key, message.getData().orElse("")).build();
|
||||
|
||||
@@ -12,7 +12,7 @@ import java.util.Optional;
|
||||
public class GcmMessage {
|
||||
|
||||
public enum Type {
|
||||
NOTIFICATION, CHALLENGE
|
||||
NOTIFICATION, CHALLENGE, RATE_LIMIT_CHALLENGE
|
||||
}
|
||||
|
||||
private final String gcmId;
|
||||
|
||||
@@ -8,6 +8,7 @@ import io.dropwizard.lifecycle.Managed;
|
||||
import io.micrometer.core.instrument.Metrics;
|
||||
import io.micrometer.core.instrument.Tag;
|
||||
import org.whispersystems.textsecuregcm.metrics.PushLatencyManager;
|
||||
import org.whispersystems.textsecuregcm.push.ApnMessage.Type;
|
||||
import org.whispersystems.textsecuregcm.redis.RedisOperation;
|
||||
import org.whispersystems.textsecuregcm.storage.Account;
|
||||
import org.whispersystems.textsecuregcm.storage.Device;
|
||||
@@ -131,10 +132,10 @@ public class MessageSender implements Managed {
|
||||
ApnMessage apnMessage;
|
||||
|
||||
if (!Util.isEmpty(device.getVoipApnId())) {
|
||||
apnMessage = new ApnMessage(device.getVoipApnId(), account.getNumber(), device.getId(), true, Optional.empty());
|
||||
apnMessage = new ApnMessage(device.getVoipApnId(), account.getNumber(), device.getId(), true, Type.NOTIFICATION, Optional.empty());
|
||||
RedisOperation.unchecked(() -> apnFallbackManager.schedule(account, device));
|
||||
} else {
|
||||
apnMessage = new ApnMessage(device.getApnId(), account.getNumber(), device.getId(), false, Optional.empty());
|
||||
apnMessage = new ApnMessage(device.getApnId(), account.getNumber(), device.getId(), false, Type.NOTIFICATION, Optional.empty());
|
||||
}
|
||||
|
||||
apnSender.sendMessage(apnMessage);
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
package org.whispersystems.textsecuregcm.push;
|
||||
|
||||
public class NotPushRegisteredException extends Exception {
|
||||
public NotPushRegisteredException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public NotPushRegisteredException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user