mirror of
https://github.com/GeyserMC/Floodgate.git
synced 2025-12-31 04:36:47 +00:00
Added a timestamp to prevent reusing the encrypted Floodgate data
This commit is contained in:
@@ -26,15 +26,11 @@
|
||||
package org.geysermc.floodgate.api;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import org.geysermc.floodgate.crypto.FloodgateCipher;
|
||||
import org.geysermc.floodgate.pluginmessage.PluginMessageManager;
|
||||
import org.geysermc.floodgate.util.BedrockData;
|
||||
|
||||
public final class ProxyFloodgateApi extends SimpleFloodgateApi {
|
||||
private final Map<UUID, String> encryptedData = new HashMap<>();
|
||||
private final FloodgateCipher cipher;
|
||||
|
||||
public ProxyFloodgateApi(PluginMessageManager pluginMessageManager, FloodgateCipher cipher) {
|
||||
@@ -42,25 +38,16 @@ public final class ProxyFloodgateApi extends SimpleFloodgateApi {
|
||||
this.cipher = cipher;
|
||||
}
|
||||
|
||||
public String getEncryptedData(UUID uuid) {
|
||||
return encryptedData.get(uuid);
|
||||
}
|
||||
|
||||
public void addEncryptedData(UUID uuid, String encryptedData) {
|
||||
this.encryptedData.put(uuid, encryptedData); // just override already existing data I guess
|
||||
}
|
||||
|
||||
public void removeEncryptedData(UUID uuid) {
|
||||
encryptedData.remove(uuid);
|
||||
}
|
||||
|
||||
public void updateEncryptedData(UUID uuid, BedrockData bedrockData) {
|
||||
public byte[] createEncryptedData(BedrockData bedrockData) {
|
||||
try {
|
||||
byte[] encryptedData = cipher.encryptFromString(bedrockData.toString());
|
||||
addEncryptedData(uuid, new String(encryptedData, StandardCharsets.UTF_8));
|
||||
return cipher.encryptFromString(bedrockData.toString());
|
||||
} catch (Exception exception) {
|
||||
throw new IllegalStateException("We failed to update the BedrockData, " +
|
||||
"but we can't continue without the updated version!", exception);
|
||||
throw new IllegalStateException("We failed to create the encrypted data, " +
|
||||
"but creating encrypted data is mandatory!", exception);
|
||||
}
|
||||
}
|
||||
|
||||
public String createEncryptedDataString(BedrockData bedrockData) {
|
||||
return new String(createEncryptedData(bedrockData), StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,11 +28,14 @@ package org.geysermc.floodgate.player;
|
||||
import static org.geysermc.floodgate.util.BedrockData.EXPECTED_LENGTH;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.util.AttributeKey;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
@@ -55,6 +58,12 @@ import org.geysermc.floodgate.util.Utils;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public final class FloodgateHandshakeHandler {
|
||||
private final Cache<String, Long> handleCache =
|
||||
CacheBuilder.newBuilder()
|
||||
.maximumSize(500)
|
||||
.expireAfterWrite(1, TimeUnit.MINUTES)
|
||||
.build();
|
||||
|
||||
private final HandshakeHandlersImpl handshakeHandlers;
|
||||
private final SimpleFloodgateApi api;
|
||||
private final FloodgateCipher cipher;
|
||||
@@ -97,6 +106,29 @@ public final class FloodgateHandshakeHandler {
|
||||
channel, bedrockData, hostname);
|
||||
}
|
||||
|
||||
// timestamp checks
|
||||
|
||||
long timeDifference = System.currentTimeMillis() - bedrockData.getTimestamp();
|
||||
if (timeDifference > 6000 || timeDifference < 0) {
|
||||
return callHandlerAndReturnResult(
|
||||
ResultType.TIMESTAMP_DENIED,
|
||||
channel, bedrockData, hostname);
|
||||
}
|
||||
|
||||
Long cachedTimestamp = handleCache.getIfPresent(bedrockData.getXuid());
|
||||
if (cachedTimestamp != null) {
|
||||
// the cached timestamp is newer than the gotten timestamp
|
||||
// you also can't reuse the data (the timestamp is there to prevent that as well)
|
||||
if (cachedTimestamp >= bedrockData.getTimestamp()) {
|
||||
return callHandlerAndReturnResult(
|
||||
ResultType.TIMESTAMP_DENIED,
|
||||
channel, bedrockData, hostname);
|
||||
}
|
||||
}
|
||||
|
||||
handleCache.put(bedrockData.getXuid(), bedrockData.getTimestamp());
|
||||
|
||||
|
||||
LinkedPlayer linkedPlayer;
|
||||
|
||||
// we'll use the LinkedPlayer provided by Bungee or Velocity (if they included one)
|
||||
@@ -212,6 +244,7 @@ public final class FloodgateHandshakeHandler {
|
||||
EXCEPTION,
|
||||
NOT_FLOODGATE_DATA,
|
||||
INVALID_DATA_LENGTH,
|
||||
TIMESTAMP_DENIED,
|
||||
SUCCESS
|
||||
}
|
||||
|
||||
|
||||
@@ -34,9 +34,9 @@ import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.floodgate.api.FloodgateApi;
|
||||
import org.geysermc.floodgate.api.InstanceHolder;
|
||||
import org.geysermc.floodgate.api.ProxyFloodgateApi;
|
||||
import org.geysermc.floodgate.api.SimpleFloodgateApi;
|
||||
import org.geysermc.floodgate.api.handshake.HandshakeData;
|
||||
import org.geysermc.floodgate.api.link.PlayerLink;
|
||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||
@@ -84,7 +84,7 @@ public final class FloodgatePlayerImpl implements FloodgatePlayer {
|
||||
BedrockData data,
|
||||
HandshakeData handshakeData) {
|
||||
|
||||
FloodgateApi api = FloodgateApi.getInstance();
|
||||
SimpleFloodgateApi api = InstanceHolder.castApi(SimpleFloodgateApi.class);
|
||||
|
||||
UUID javaUniqueId = Utils.getJavaUuid(data.getXuid());
|
||||
|
||||
@@ -94,18 +94,11 @@ public final class FloodgatePlayerImpl implements FloodgatePlayer {
|
||||
|
||||
LinkedPlayer linkedPlayer = handshakeData.getLinkedPlayer();
|
||||
|
||||
FloodgatePlayerImpl player = new FloodgatePlayerImpl(
|
||||
return new FloodgatePlayerImpl(
|
||||
data.getVersion(), data.getUsername(), handshakeData.getJavaUsername(),
|
||||
javaUniqueId, data.getXuid(), deviceOs, data.getLanguageCode(), uiProfile,
|
||||
inputMode, data.getIp(), data.isFromProxy(), api instanceof ProxyFloodgateApi,
|
||||
linkedPlayer, data.getSubscribeId(), data.getVerifyCode());
|
||||
|
||||
// fromProxy and linked player might have to be changed
|
||||
if (api instanceof ProxyFloodgateApi) {
|
||||
InstanceHolder.castApi(ProxyFloodgateApi.class)
|
||||
.updateEncryptedData(player.getCorrectUniqueId(), player.toBedrockData());
|
||||
}
|
||||
return player;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,4 +31,8 @@ public final class Constants {
|
||||
public static final String WEBSOCKET_URL = "wss://api.geysermc.org/ws";
|
||||
|
||||
public static final boolean DEBUG_MODE = true;
|
||||
|
||||
public static final String TIMESTAMP_DENIED_MESSAGE =
|
||||
"Something isn't right with this data." +
|
||||
" Try logging in again or contact a server administrator if the issue persists.";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user