From f25673dcaadc06bcd5705b9656e0893a42db5bb0 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sat, 30 Sep 2023 17:43:03 +0200 Subject: [PATCH] Updated a few dependencies and made it easier to run on Geyser --- .../floodgate/bungee/BungeePlatform.java | 2 +- .../bungee/module/BungeePlatformModule.java | 4 +- .../bungee/util/BungeeCommandUtil.java | 6 +- .../floodgate/core/FloodgatePlatform.java | 2 +- .../core/addon/data/CommonDataHandler.java | 6 +- .../core/addon/data/HandshakeDataImpl.java | 4 +- .../floodgate/core/api/ProxyFloodgateApi.java | 4 +- .../core/command/LinkAccountCommand.java | 4 +- .../floodgate/core/command/TestCommand.java | 2 +- .../core/command/UnlinkAccountCommand.java | 4 +- .../core/command/WhitelistCommand.java | 2 +- .../command/main/FirewallCheckSubcommand.java | 2 +- .../core/command/main/MainCommand.java | 2 +- .../core/command/main/VersionSubcommand.java | 2 +- .../floodgate/core/config/ConfigLoader.java | 5 +- .../core/connection/FloodgateConnection.java | 103 +----------- .../FloodgateConnectionBuilder.java | 14 +- .../connection/FloodgateHandshakeHandler.java | 43 +++-- .../StandaloneFloodgateConnection.java | 101 ++++++++++++ .../FloodgateCommandPreprocessor.java | 2 +- .../audience/ProfileAudienceArgument.java | 1 - .../{ => audience}/UserAudience.java | 2 +- .../core/connection/codec/CodecUtils.java | 1 + .../codec/FloodgateConnectionCodec.java | 4 +- .../core/crypto/FloodgateDataCodec.java | 144 ++--------------- .../core/crypto/FloodgateFormatCodec.java | 150 ++++++++++++++++++ .../UnsupportedVersionException.java | 7 + .../floodgate/core/link/PlayerLinkJdbc.java | 2 + .../floodgate/core/module/CommonModule.java | 20 --- .../core/platform/command/CommandUtil.java | 2 +- .../platform/command/FloodgateCommand.java | 2 +- .../platform/command/FloodgateSubCommand.java | 2 +- .../core/register/CommandRegister.java | 2 +- .../core/util/InvalidFormatException.java | 2 +- ...est.java => FloodgateFormatCodecTest.java} | 50 +++--- gradle.properties | 2 +- gradle/libs.versions.toml | 8 +- .../floodgate/spigot/SpigotPlatform.java | 2 +- .../spigot/command/SpigotCommandManager.java | 4 +- .../spigot/util/SpigotCommandUtil.java | 6 +- .../floodgate/velocity/VelocityPlatform.java | 2 +- .../module/VelocityPlatformModule.java | 4 +- .../velocity/util/VelocityCommandUtil.java | 6 +- 43 files changed, 393 insertions(+), 346 deletions(-) create mode 100644 core/src/main/java/org/geysermc/floodgate/core/connection/StandaloneFloodgateConnection.java rename core/src/main/java/org/geysermc/floodgate/core/connection/{ => audience}/FloodgateCommandPreprocessor.java (97%) rename core/src/main/java/org/geysermc/floodgate/core/connection/{ => audience}/UserAudience.java (98%) create mode 100644 core/src/main/java/org/geysermc/floodgate/core/crypto/FloodgateFormatCodec.java create mode 100644 core/src/main/java/org/geysermc/floodgate/core/crypto/exception/UnsupportedVersionException.java rename core/src/test/java/org/geysermc/floodgate/core/crypto/{FloodgateDataCodecTest.java => FloodgateFormatCodecTest.java} (80%) diff --git a/bungee/base/src/main/java/org/geysermc/floodgate/bungee/BungeePlatform.java b/bungee/base/src/main/java/org/geysermc/floodgate/bungee/BungeePlatform.java index dece3ff3..e59984ab 100644 --- a/bungee/base/src/main/java/org/geysermc/floodgate/bungee/BungeePlatform.java +++ b/bungee/base/src/main/java/org/geysermc/floodgate/bungee/BungeePlatform.java @@ -56,7 +56,7 @@ public class BungeePlatform extends FloodgatePlatform { } @Override - protected boolean isProxy() { + public boolean isProxy() { return true; } } diff --git a/bungee/base/src/main/java/org/geysermc/floodgate/bungee/module/BungeePlatformModule.java b/bungee/base/src/main/java/org/geysermc/floodgate/bungee/module/BungeePlatformModule.java index b6699b70..4b60cbe9 100644 --- a/bungee/base/src/main/java/org/geysermc/floodgate/bungee/module/BungeePlatformModule.java +++ b/bungee/base/src/main/java/org/geysermc/floodgate/bungee/module/BungeePlatformModule.java @@ -34,8 +34,8 @@ import jakarta.inject.Named; import jakarta.inject.Singleton; import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.plugin.Plugin; -import org.geysermc.floodgate.core.connection.FloodgateCommandPreprocessor; -import org.geysermc.floodgate.core.connection.UserAudience; +import org.geysermc.floodgate.core.connection.audience.FloodgateCommandPreprocessor; +import org.geysermc.floodgate.core.connection.audience.UserAudience; import org.geysermc.floodgate.core.platform.command.CommandUtil; @Factory diff --git a/bungee/base/src/main/java/org/geysermc/floodgate/bungee/util/BungeeCommandUtil.java b/bungee/base/src/main/java/org/geysermc/floodgate/bungee/util/BungeeCommandUtil.java index 487b608c..db5e3916 100644 --- a/bungee/base/src/main/java/org/geysermc/floodgate/bungee/util/BungeeCommandUtil.java +++ b/bungee/base/src/main/java/org/geysermc/floodgate/bungee/util/BungeeCommandUtil.java @@ -34,9 +34,9 @@ import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.connection.ProxiedPlayer; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.api.GeyserApiBase; -import org.geysermc.floodgate.core.connection.UserAudience; -import org.geysermc.floodgate.core.connection.UserAudience.ConsoleAudience; -import org.geysermc.floodgate.core.connection.UserAudience.PlayerAudience; +import org.geysermc.floodgate.core.connection.audience.UserAudience; +import org.geysermc.floodgate.core.connection.audience.UserAudience.ConsoleAudience; +import org.geysermc.floodgate.core.connection.audience.UserAudience.PlayerAudience; import org.geysermc.floodgate.core.platform.command.CommandUtil; import org.geysermc.floodgate.core.util.LanguageManager; import org.geysermc.floodgate.core.util.Utils; diff --git a/core/src/main/java/org/geysermc/floodgate/core/FloodgatePlatform.java b/core/src/main/java/org/geysermc/floodgate/core/FloodgatePlatform.java index 9e3fb5d7..b2aa1291 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/FloodgatePlatform.java +++ b/core/src/main/java/org/geysermc/floodgate/core/FloodgatePlatform.java @@ -124,7 +124,7 @@ public abstract class FloodgatePlatform { context.close(); } - abstract protected boolean isProxy(); + abstract public boolean isProxy(); public T getBean(Class clazz) { return context.getBean(clazz); diff --git a/core/src/main/java/org/geysermc/floodgate/core/addon/data/CommonDataHandler.java b/core/src/main/java/org/geysermc/floodgate/core/addon/data/CommonDataHandler.java index 6ce9d5ff..30fe1f7a 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/addon/data/CommonDataHandler.java +++ b/core/src/main/java/org/geysermc/floodgate/core/addon/data/CommonDataHandler.java @@ -38,7 +38,7 @@ import org.geysermc.floodgate.core.config.FloodgateConfig; import org.geysermc.floodgate.core.connection.FloodgateHandshakeHandler; import org.geysermc.floodgate.core.connection.FloodgateHandshakeHandler.HandshakeResult; import org.geysermc.floodgate.core.connection.HostnameSeparationResult; -import org.geysermc.floodgate.core.crypto.FloodgateDataCodec; +import org.geysermc.floodgate.core.crypto.FloodgateFormatCodec; import org.geysermc.floodgate.core.util.Constants; @RequiredArgsConstructor @@ -76,11 +76,11 @@ public abstract class CommonDataHandler extends ChannelInboundHandlerAdapter { return; } - if (separation.headerVersion() != FloodgateDataCodec.VERSION) { + if (separation.headerVersion() != FloodgateFormatCodec.VERSION) { disablePacketQueue(true); setKickMessage(String.format( Constants.UNSUPPORTED_DATA_VERSION, - FloodgateDataCodec.VERSION, separation.headerVersion() + FloodgateFormatCodec.VERSION, separation.headerVersion() )); return; } diff --git a/core/src/main/java/org/geysermc/floodgate/core/addon/data/HandshakeDataImpl.java b/core/src/main/java/org/geysermc/floodgate/core/addon/data/HandshakeDataImpl.java index ee3a7295..41ceb020 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/addon/data/HandshakeDataImpl.java +++ b/core/src/main/java/org/geysermc/floodgate/core/addon/data/HandshakeDataImpl.java @@ -82,7 +82,7 @@ public class HandshakeDataImpl implements HandshakeData { this.javaUniqueId = javaUniqueId; } - public FloodgateConnection applyChanges(FloodgateConnection connection, String hostname, FloodgateConfig config) { + public FloodgateConnection applyChanges(FloodgateConnection connection, FloodgateConfig config) { var newLink = !Objects.equals(connection.linkedPlayer(), this.linkedPlayer) ? this.linkedPlayer : null; var thisIp = convertIp(this.ip); @@ -94,7 +94,7 @@ public class HandshakeDataImpl implements HandshakeData { } var builder = new FloodgateConnectionBuilder(config); - connection.fillBuilder(builder); +// connection.fillBuilder(builder); todo probably remove handshake handlers all together if (newLink != null) builder.linkedPlayer(newLink); if (newIp != null) builder.ip(newIp); return builder.build(); diff --git a/core/src/main/java/org/geysermc/floodgate/core/api/ProxyFloodgateApi.java b/core/src/main/java/org/geysermc/floodgate/core/api/ProxyFloodgateApi.java index a1cc5133..339eb08e 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/api/ProxyFloodgateApi.java +++ b/core/src/main/java/org/geysermc/floodgate/core/api/ProxyFloodgateApi.java @@ -28,14 +28,14 @@ package org.geysermc.floodgate.core.api; import jakarta.inject.Inject; import jakarta.inject.Singleton; import java.nio.charset.StandardCharsets; -import org.geysermc.floodgate.core.crypto.FloodgateDataCodec; +import org.geysermc.floodgate.core.crypto.FloodgateFormatCodec; import org.geysermc.floodgate.core.scope.ProxyOnly; import org.geysermc.floodgate.util.BedrockData; @ProxyOnly @Singleton public final class ProxyFloodgateApi extends SimpleFloodgateApi { - @Inject FloodgateDataCodec dataCodec; + @Inject FloodgateFormatCodec dataCodec; public byte[] createEncryptedData(BedrockData bedrockData) { try { diff --git a/core/src/main/java/org/geysermc/floodgate/core/command/LinkAccountCommand.java b/core/src/main/java/org/geysermc/floodgate/core/command/LinkAccountCommand.java index 7b98b94f..480f5d56 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/command/LinkAccountCommand.java +++ b/core/src/main/java/org/geysermc/floodgate/core/command/LinkAccountCommand.java @@ -39,10 +39,10 @@ import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.core.api.SimpleFloodgateApi; import org.geysermc.floodgate.core.command.util.Permission; import org.geysermc.floodgate.core.config.FloodgateConfig; -import org.geysermc.floodgate.core.connection.UserAudience; -import org.geysermc.floodgate.core.connection.UserAudience.PlayerAudience; import org.geysermc.floodgate.core.connection.audience.ProfileAudience; import org.geysermc.floodgate.core.connection.audience.ProfileAudienceArgument; +import org.geysermc.floodgate.core.connection.audience.UserAudience; +import org.geysermc.floodgate.core.connection.audience.UserAudience.PlayerAudience; import org.geysermc.floodgate.core.link.CommonPlayerLink; import org.geysermc.floodgate.core.link.GlobalPlayerLinking; import org.geysermc.floodgate.core.link.LinkVerificationException; diff --git a/core/src/main/java/org/geysermc/floodgate/core/command/TestCommand.java b/core/src/main/java/org/geysermc/floodgate/core/command/TestCommand.java index 50c7f7bb..e970aa54 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/command/TestCommand.java +++ b/core/src/main/java/org/geysermc/floodgate/core/command/TestCommand.java @@ -31,7 +31,7 @@ import cloud.commandframework.context.CommandContext; import jakarta.inject.Singleton; import org.geysermc.api.Geyser; import org.geysermc.floodgate.core.config.FloodgateConfig; -import org.geysermc.floodgate.core.connection.UserAudience; +import org.geysermc.floodgate.core.connection.audience.UserAudience; import org.geysermc.floodgate.core.platform.command.FloodgateCommand; import org.geysermc.floodgate.core.util.Constants; diff --git a/core/src/main/java/org/geysermc/floodgate/core/command/UnlinkAccountCommand.java b/core/src/main/java/org/geysermc/floodgate/core/command/UnlinkAccountCommand.java index 968172c0..32697b55 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/command/UnlinkAccountCommand.java +++ b/core/src/main/java/org/geysermc/floodgate/core/command/UnlinkAccountCommand.java @@ -34,8 +34,8 @@ import jakarta.inject.Singleton; import lombok.Getter; import org.geysermc.floodgate.core.command.util.Permission; import org.geysermc.floodgate.core.config.FloodgateConfig; -import org.geysermc.floodgate.core.connection.UserAudience; -import org.geysermc.floodgate.core.connection.UserAudience.PlayerAudience; +import org.geysermc.floodgate.core.connection.audience.UserAudience; +import org.geysermc.floodgate.core.connection.audience.UserAudience.PlayerAudience; import org.geysermc.floodgate.core.link.CommonPlayerLink; import org.geysermc.floodgate.core.link.GlobalPlayerLinking; import org.geysermc.floodgate.core.platform.command.FloodgateCommand; diff --git a/core/src/main/java/org/geysermc/floodgate/core/command/WhitelistCommand.java b/core/src/main/java/org/geysermc/floodgate/core/command/WhitelistCommand.java index 98d605dd..f62c1ce0 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/command/WhitelistCommand.java +++ b/core/src/main/java/org/geysermc/floodgate/core/command/WhitelistCommand.java @@ -38,9 +38,9 @@ import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.core.command.util.Permission; import org.geysermc.floodgate.core.config.FloodgateConfig; import org.geysermc.floodgate.core.config.ProxyFloodgateConfig; -import org.geysermc.floodgate.core.connection.UserAudience; import org.geysermc.floodgate.core.connection.audience.ProfileAudience; import org.geysermc.floodgate.core.connection.audience.ProfileAudienceArgument; +import org.geysermc.floodgate.core.connection.audience.UserAudience; import org.geysermc.floodgate.core.http.xbox.XboxClient; import org.geysermc.floodgate.core.platform.command.CommandUtil; import org.geysermc.floodgate.core.platform.command.FloodgateCommand; diff --git a/core/src/main/java/org/geysermc/floodgate/core/command/main/FirewallCheckSubcommand.java b/core/src/main/java/org/geysermc/floodgate/core/command/main/FirewallCheckSubcommand.java index 92968853..941d3b2b 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/command/main/FirewallCheckSubcommand.java +++ b/core/src/main/java/org/geysermc/floodgate/core/command/main/FirewallCheckSubcommand.java @@ -35,7 +35,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BooleanSupplier; import org.geysermc.floodgate.core.command.util.Permission; -import org.geysermc.floodgate.core.connection.UserAudience; +import org.geysermc.floodgate.core.connection.audience.UserAudience; import org.geysermc.floodgate.core.platform.command.FloodgateSubCommand; import org.geysermc.floodgate.core.util.Constants; import org.geysermc.floodgate.core.util.HttpClient; diff --git a/core/src/main/java/org/geysermc/floodgate/core/command/main/MainCommand.java b/core/src/main/java/org/geysermc/floodgate/core/command/main/MainCommand.java index 3c5d7bdc..810c2c06 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/command/main/MainCommand.java +++ b/core/src/main/java/org/geysermc/floodgate/core/command/main/MainCommand.java @@ -35,7 +35,7 @@ import cloud.commandframework.context.CommandContext; import jakarta.inject.Singleton; import java.util.Locale; import org.geysermc.floodgate.core.command.util.Permission; -import org.geysermc.floodgate.core.connection.UserAudience; +import org.geysermc.floodgate.core.connection.audience.UserAudience; import org.geysermc.floodgate.core.platform.command.FloodgateCommand; import org.geysermc.floodgate.core.platform.command.FloodgateSubCommand; import org.geysermc.floodgate.core.platform.command.SubCommands; diff --git a/core/src/main/java/org/geysermc/floodgate/core/command/main/VersionSubcommand.java b/core/src/main/java/org/geysermc/floodgate/core/command/main/VersionSubcommand.java index 9fdc65c7..3915aeee 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/command/main/VersionSubcommand.java +++ b/core/src/main/java/org/geysermc/floodgate/core/command/main/VersionSubcommand.java @@ -33,7 +33,7 @@ import jakarta.inject.Inject; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.core.command.WhitelistCommand.Message; import org.geysermc.floodgate.core.command.util.Permission; -import org.geysermc.floodgate.core.connection.UserAudience; +import org.geysermc.floodgate.core.connection.audience.UserAudience; import org.geysermc.floodgate.core.platform.command.FloodgateSubCommand; import org.geysermc.floodgate.core.util.Constants; import org.geysermc.floodgate.core.util.HttpClient; diff --git a/core/src/main/java/org/geysermc/floodgate/core/config/ConfigLoader.java b/core/src/main/java/org/geysermc/floodgate/core/config/ConfigLoader.java index 27826796..19507259 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/config/ConfigLoader.java +++ b/core/src/main/java/org/geysermc/floodgate/core/config/ConfigLoader.java @@ -37,7 +37,6 @@ import lombok.Getter; import org.geysermc.configutils.ConfigUtilities; import org.geysermc.configutils.file.codec.PathFileCodec; import org.geysermc.configutils.updater.change.Changes; -import org.geysermc.floodgate.core.crypto.FloodgateDataCodec; import org.geysermc.floodgate.core.scope.ProxyOnly; import org.geysermc.floodgate.core.scope.ServerOnly; import org.geysermc.floodgate.core.util.GlobalBeanCache; @@ -47,12 +46,10 @@ import org.geysermc.floodgate.core.util.GlobalBeanCache; @BootstrapContextCompatible public final class ConfigLoader { private final Path dataDirectory; - private final FloodgateDataCodec dataCodec; @Inject - ConfigLoader(@Named("dataDirectory") Path dataDirectory, FloodgateDataCodec dataCodec) { + ConfigLoader(@Named("dataDirectory") Path dataDirectory) { this.dataDirectory = dataDirectory; - this.dataCodec = dataCodec; } @Bean diff --git a/core/src/main/java/org/geysermc/floodgate/core/connection/FloodgateConnection.java b/core/src/main/java/org/geysermc/floodgate/core/connection/FloodgateConnection.java index 98674b90..e6a91b9a 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/connection/FloodgateConnection.java +++ b/core/src/main/java/org/geysermc/floodgate/core/connection/FloodgateConnection.java @@ -27,17 +27,11 @@ package org.geysermc.floodgate.core.connection; import java.net.InetAddress; import java.util.UUID; -import lombok.AccessLevel; -import lombok.RequiredArgsConstructor; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.common.value.qual.IntRange; import org.geysermc.api.Geyser; import org.geysermc.api.connection.Connection; -import org.geysermc.api.util.BedrockPlatform; -import org.geysermc.api.util.InputMode; -import org.geysermc.api.util.UiProfile; import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.form.util.FormBuilder; import org.geysermc.floodgate.core.api.legacy.LegacyPlayerWrapper; @@ -45,87 +39,19 @@ import org.geysermc.floodgate.core.api.legacy.PropertyGlue; import org.geysermc.floodgate.util.BedrockData; import org.geysermc.floodgate.util.LinkedPlayer; -@RequiredArgsConstructor(access = AccessLevel.PACKAGE) -public final class FloodgateConnection implements Connection { - private final String version; - private final String username; - private final UUID identifier; - private final String xuid; - private final String javaUsername; - private final UUID javaUniqueId; - private final BedrockPlatform deviceOs; - private final String languageCode; - private final UiProfile uiProfile; - private final InputMode inputMode; - private final InetAddress ip; - private final LinkedPlayer linkedPlayer; - - private final int subscribeId; - private final String verifyCode; - +public abstract class FloodgateConnection implements Connection { private final PropertyGlue propertyGlue = new PropertyGlue(); private LegacyPlayerWrapper legacyPlayer; - @Override - public @NonNull String bedrockUsername() { - return username; - } + public abstract @NonNull UUID identity(); - public @NonNull UUID identifier() { - return identifier; - } + public abstract @NonNull InetAddress ip(); - @Override - public @NonNull String xuid() { - return xuid; - } - - @Override - public @MonotonicNonNull String javaUsername() { - return linkedPlayer != null ? linkedPlayer.getJavaUsername() : javaUsername; - } - - @Override - public @MonotonicNonNull UUID javaUuid() { - return linkedPlayer != null ? linkedPlayer.getJavaUniqueId() : javaUniqueId; - } - - @Override - public @NonNull String version() { - return version; - } - - @Override - public @NonNull BedrockPlatform platform() { - return deviceOs; - } - - @Override - public @NonNull String languageCode() { - return languageCode; - } - - @Override - public @NonNull UiProfile uiProfile() { - return uiProfile; - } - - @Override - public @NonNull InputMode inputMode() { - return inputMode; - } - - public @NonNull InetAddress ip() { - return ip; - } + public abstract @MonotonicNonNull LinkedPlayer linkedPlayer(); @Override public boolean isLinked() { - return linkedPlayer != null; - } - - public @Nullable LinkedPlayer linkedPlayer() { - return linkedPlayer; + return linkedPlayer() != null; } @Override @@ -143,29 +69,16 @@ public final class FloodgateConnection implements Connection { return Geyser.api().transfer(javaUuid(), address, port); } - public void fillBuilder(FloodgateConnectionBuilder builder) { - builder.version(version) - .username(username) - .identifier(identifier) - .xuid(xuid) - .deviceOs(deviceOs) - .languageCode(languageCode) - .uiProfile(uiProfile) - .inputMode(inputMode) - .ip(ip) - .linkedPlayer(linkedPlayer); - } - public BedrockData toBedrockData() { return BedrockData.of( - version, username, xuid, deviceOs.ordinal(), languageCode, uiProfile.ordinal(), - inputMode.ordinal(), ip.getHostAddress(), linkedPlayer, false, subscribeId, verifyCode + version(), bedrockUsername(), xuid(), platform().ordinal(), languageCode(), uiProfile().ordinal(), + inputMode().ordinal(), ip().getHostAddress(), linkedPlayer(), false, 0, null ); } public LegacyPlayerWrapper legacySelf() { if (legacyPlayer == null) { - legacyPlayer = new LegacyPlayerWrapper(this, javaUsername, javaUniqueId); + legacyPlayer = new LegacyPlayerWrapper(this, javaUsername(), javaUuid()); } return legacyPlayer; } diff --git a/core/src/main/java/org/geysermc/floodgate/core/connection/FloodgateConnectionBuilder.java b/core/src/main/java/org/geysermc/floodgate/core/connection/FloodgateConnectionBuilder.java index b9756c35..c965da8b 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/connection/FloodgateConnectionBuilder.java +++ b/core/src/main/java/org/geysermc/floodgate/core/connection/FloodgateConnectionBuilder.java @@ -41,7 +41,7 @@ public class FloodgateConnectionBuilder { private final FloodgateConfig config; private String version; private String username; - private UUID identifier; + private UUID identity; private String xuid; private BedrockPlatform deviceOs; private String languageCode; @@ -64,8 +64,8 @@ public class FloodgateConnectionBuilder { return this; } - public @This FloodgateConnectionBuilder identifier(UUID identifier) { - this.identifier = Objects.requireNonNull(identifier); + public @This FloodgateConnectionBuilder identity(UUID identity) { + this.identity = Objects.requireNonNull(identity); return this; } @@ -108,10 +108,10 @@ public class FloodgateConnectionBuilder { // todo add an option to use identity instead of xuid UUID javaUniqueId = Utils.getJavaUuid(xuid); - return new FloodgateConnection( + return new StandaloneFloodgateConnection( version, username, - identifier, + identity, xuid, javaUsername(), javaUniqueId, @@ -120,9 +120,7 @@ public class FloodgateConnectionBuilder { uiProfile, inputMode, ip, - linkedPlayer, - 0, - null + linkedPlayer ); } diff --git a/core/src/main/java/org/geysermc/floodgate/core/connection/FloodgateHandshakeHandler.java b/core/src/main/java/org/geysermc/floodgate/core/connection/FloodgateHandshakeHandler.java index cb0f0150..575202c1 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/connection/FloodgateHandshakeHandler.java +++ b/core/src/main/java/org/geysermc/floodgate/core/connection/FloodgateHandshakeHandler.java @@ -34,7 +34,6 @@ import jakarta.inject.Inject; import jakarta.inject.Named; import jakarta.inject.Singleton; import java.net.InetSocketAddress; -import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; @@ -51,6 +50,8 @@ import org.geysermc.floodgate.core.api.SimpleFloodgateApi; import org.geysermc.floodgate.core.config.FloodgateConfig; import org.geysermc.floodgate.core.connection.codec.FloodgateConnectionCodec; import org.geysermc.floodgate.core.crypto.FloodgateDataCodec; +import org.geysermc.floodgate.core.crypto.FloodgateFormatCodec; +import org.geysermc.floodgate.core.crypto.exception.UnsupportedVersionException; import org.geysermc.floodgate.core.link.CommonPlayerLink; import org.geysermc.floodgate.core.skin.SkinUploadManager; import org.geysermc.floodgate.core.util.Constants; @@ -89,7 +90,7 @@ public final class FloodgateHandshakeHandler { StringBuilder builder = new StringBuilder(); for (String value : hostnameItems) { - int version = FloodgateDataCodec.version(value); + int version = FloodgateFormatCodec.version(value); if (floodgateData == null && version != -1) { floodgateData = value; dataVersion = version; @@ -110,36 +111,32 @@ public final class FloodgateHandshakeHandler { @NonNull String floodgateDataString, @NonNull String hostname ) { + System.out.println("received: " + floodgateDataString); byte[] floodgateData = floodgateDataString.getBytes(StandardCharsets.UTF_8); return CompletableFuture.supplyAsync(() -> { - ByteBuffer decoded; - try { - // the actual decryption of the data - decoded = dataCodec.decode(floodgateData); - } catch (InvalidFormatException e) { - // when the Floodgate format couldn't be found - throw callHandlerAndReturnResult(NOT_FLOODGATE_DATA, channel, hostname); - } catch (Exception exception) { - // all the other exceptions are caused by invalid/tempered Floodgate data - if (config.debug()) { - exception.printStackTrace(); - } - - throw callHandlerAndReturnResult(ResultType.DECRYPT_ERROR, channel, hostname); - } - FloodgateConnection connection; try { - connection = connectionCodec.decode(decoded); - } catch (Exception exception) { - // todo probably add a format version as that's the most likely reason for this error + // the actual decrypt/verify of the data + connection = dataCodec.decode(floodgateData); + } catch (InvalidFormatException exception) { + // when the Floodgate format couldn't be found + throw callHandlerAndReturnResult(NOT_FLOODGATE_DATA, channel, hostname); + } catch (UnsupportedVersionException exception) { + // unsupported format version if (config.debug()) { exception.printStackTrace(); } throw callHandlerAndReturnResult(INVALID_DATA, channel, hostname); + } catch (Exception exception) { + // all the other exceptions are caused by invalid/tempered Floodgate data + if (config.debug() || true) { + exception.printStackTrace(); + } + + throw callHandlerAndReturnResult(ResultType.DECRYPT_ERROR, channel, hostname); } try { @@ -206,9 +203,11 @@ public final class FloodgateHandshakeHandler { // bedrockData.getVerifyCode()); // } - connection = handshakeData.applyChanges(connection, hostname, config); + connection = handshakeData.applyChanges(connection, config); connectionManager.addConnection(connection); + //todo when splitting up between netty and non-netty make a NettyConnectionManager which + // uses the channel as argument to set the attribute channel.attr(playerAttribute).set(connection); return new HandshakeResult(ResultType.SUCCESS, handshakeData, connection); diff --git a/core/src/main/java/org/geysermc/floodgate/core/connection/StandaloneFloodgateConnection.java b/core/src/main/java/org/geysermc/floodgate/core/connection/StandaloneFloodgateConnection.java new file mode 100644 index 00000000..69c3aa50 --- /dev/null +++ b/core/src/main/java/org/geysermc/floodgate/core/connection/StandaloneFloodgateConnection.java @@ -0,0 +1,101 @@ +package org.geysermc.floodgate.core.connection; + +import java.net.InetAddress; +import java.util.UUID; +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.api.util.BedrockPlatform; +import org.geysermc.api.util.InputMode; +import org.geysermc.api.util.UiProfile; +import org.geysermc.floodgate.util.LinkedPlayer; + +@RequiredArgsConstructor(access = AccessLevel.PACKAGE) +public final class StandaloneFloodgateConnection extends FloodgateConnection { + private final String version; + private final String username; + private final UUID identity; + private final String xuid; + private final String javaUsername; + private final UUID javaUniqueId; + private final BedrockPlatform deviceOs; + private final String languageCode; + private final UiProfile uiProfile; + private final InputMode inputMode; + private final InetAddress ip; + private final LinkedPlayer linkedPlayer; + + @Override + public @NonNull String bedrockUsername() { + return username; + } + + public @NonNull UUID identity() { + return identity; + } + + @Override + public @NonNull String xuid() { + return xuid; + } + + @Override + public @MonotonicNonNull String javaUsername() { + return linkedPlayer != null ? linkedPlayer.getJavaUsername() : javaUsername; + } + + @Override + public @MonotonicNonNull UUID javaUuid() { + return linkedPlayer != null ? linkedPlayer.getJavaUniqueId() : javaUniqueId; + } + + @Override + public @NonNull String version() { + return version; + } + + @Override + public @NonNull BedrockPlatform platform() { + return deviceOs; + } + + @Override + public @NonNull String languageCode() { + return languageCode; + } + + @Override + public @NonNull UiProfile uiProfile() { + return uiProfile; + } + + @Override + public @NonNull InputMode inputMode() { + return inputMode; + } + + @Override + public @NonNull InetAddress ip() { + return ip; + } + + @Override + public @Nullable LinkedPlayer linkedPlayer() { + return linkedPlayer; + } + + public void fillBuilder(FloodgateConnectionBuilder builder) { + builder.version(version) + .username(username) + .identity(identity) + .xuid(xuid) + .deviceOs(deviceOs) + .languageCode(languageCode) + .uiProfile(uiProfile) + .inputMode(inputMode) + .ip(ip) + .linkedPlayer(linkedPlayer); + } +} diff --git a/core/src/main/java/org/geysermc/floodgate/core/connection/FloodgateCommandPreprocessor.java b/core/src/main/java/org/geysermc/floodgate/core/connection/audience/FloodgateCommandPreprocessor.java similarity index 97% rename from core/src/main/java/org/geysermc/floodgate/core/connection/FloodgateCommandPreprocessor.java rename to core/src/main/java/org/geysermc/floodgate/core/connection/audience/FloodgateCommandPreprocessor.java index fb39f954..71411705 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/connection/FloodgateCommandPreprocessor.java +++ b/core/src/main/java/org/geysermc/floodgate/core/connection/audience/FloodgateCommandPreprocessor.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Floodgate */ -package org.geysermc.floodgate.core.connection; +package org.geysermc.floodgate.core.connection.audience; import cloud.commandframework.execution.preprocessor.CommandPreprocessingContext; import cloud.commandframework.execution.preprocessor.CommandPreprocessor; diff --git a/core/src/main/java/org/geysermc/floodgate/core/connection/audience/ProfileAudienceArgument.java b/core/src/main/java/org/geysermc/floodgate/core/connection/audience/ProfileAudienceArgument.java index 5fe89e4a..41d08192 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/connection/audience/ProfileAudienceArgument.java +++ b/core/src/main/java/org/geysermc/floodgate/core/connection/audience/ProfileAudienceArgument.java @@ -37,7 +37,6 @@ import java.util.Queue; import java.util.UUID; import lombok.RequiredArgsConstructor; import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.floodgate.core.connection.UserAudience; import org.geysermc.floodgate.core.platform.command.CommandUtil; import org.geysermc.floodgate.core.platform.util.PlayerType; diff --git a/core/src/main/java/org/geysermc/floodgate/core/connection/UserAudience.java b/core/src/main/java/org/geysermc/floodgate/core/connection/audience/UserAudience.java similarity index 98% rename from core/src/main/java/org/geysermc/floodgate/core/connection/UserAudience.java rename to core/src/main/java/org/geysermc/floodgate/core/connection/audience/UserAudience.java index 12233b1b..3b1b497f 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/connection/UserAudience.java +++ b/core/src/main/java/org/geysermc/floodgate/core/connection/audience/UserAudience.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Floodgate */ -package org.geysermc.floodgate.core.connection; +package org.geysermc.floodgate.core.connection.audience; import java.util.Objects; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/floodgate/core/connection/codec/CodecUtils.java b/core/src/main/java/org/geysermc/floodgate/core/connection/codec/CodecUtils.java index fd4327cb..b800144e 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/connection/codec/CodecUtils.java +++ b/core/src/main/java/org/geysermc/floodgate/core/connection/codec/CodecUtils.java @@ -42,6 +42,7 @@ final class CodecUtils { public static String readString(ByteBuffer buffer) { var bytes = new byte[readVarInt(buffer)]; + buffer.get(bytes); return new String(bytes, StandardCharsets.UTF_8); } diff --git a/core/src/main/java/org/geysermc/floodgate/core/connection/codec/FloodgateConnectionCodec.java b/core/src/main/java/org/geysermc/floodgate/core/connection/codec/FloodgateConnectionCodec.java index e9b146ad..9cf5dbff 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/connection/codec/FloodgateConnectionCodec.java +++ b/core/src/main/java/org/geysermc/floodgate/core/connection/codec/FloodgateConnectionCodec.java @@ -66,7 +66,7 @@ public final class FloodgateConnectionCodec { private void encode0(FloodgateConnection connection, DataOutputStream stream) throws IOException { writeString(stream, connection.version()); writeString(stream, connection.bedrockUsername()); - writeUniqueId(stream, connection.identifier()); + writeUniqueId(stream, connection.identity()); writeUnsignedLong(stream, connection.xuid()); stream.writeByte(connection.platform().ordinal()); writeString(stream, connection.languageCode()); @@ -84,7 +84,7 @@ public final class FloodgateConnectionCodec { var builder = new FloodgateConnectionBuilder(config) .version(readString(buffer)) .username(readString(buffer)) - .identifier(readUniqueId(buffer)) + .identity(readUniqueId(buffer)) .xuid(readUnsignedLong(buffer)) .deviceOs(BedrockPlatform.fromId(buffer.get())) .languageCode(readString(buffer)) diff --git a/core/src/main/java/org/geysermc/floodgate/core/crypto/FloodgateDataCodec.java b/core/src/main/java/org/geysermc/floodgate/core/crypto/FloodgateDataCodec.java index 60b3df12..8f0c3b90 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/crypto/FloodgateDataCodec.java +++ b/core/src/main/java/org/geysermc/floodgate/core/crypto/FloodgateDataCodec.java @@ -1,141 +1,29 @@ -/* - * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Floodgate - */ - package org.geysermc.floodgate.core.crypto; -import static java.nio.charset.StandardCharsets.UTF_8; - -import jakarta.inject.Named; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.file.Path; -import java.util.Objects; -import org.geysermc.floodgate.core.crypto.topping.Topping; -import org.geysermc.floodgate.core.util.InvalidFormatException; +import jakarta.inject.Singleton; +import java.nio.charset.StandardCharsets; +import org.geysermc.floodgate.core.connection.FloodgateConnection; +import org.geysermc.floodgate.core.connection.codec.FloodgateConnectionCodec; +@Singleton public final class FloodgateDataCodec { - public static final int VERSION = 2; - public static final byte[] IDENTIFIER = "^Floodgate^".getBytes(UTF_8); - public static final byte[] HEADER = (new String(IDENTIFIER, UTF_8) + (char) (VERSION + 0x3D)).getBytes(UTF_8); + private final FloodgateFormatCodec formatCodec; + private final FloodgateConnectionCodec connectionCodec; - private final DataCodec codec; - - private final Topping topping; - - public FloodgateDataCodec( - DataCodecType type, - Topping topping, - @Named("dataDirectory") Path dataDirectory - ) throws IOException { - Objects.requireNonNull(type); - this.codec = type.dataCodec(); - this.topping = topping; - - var keyCodecBase = type.keyCodec(); - if (type.asymmetrical()) { - var keyPair = ((KeyCodecPair) keyCodecBase).decode(dataDirectory); - ((DataCodecKeyPair) codec).init(keyPair); - } else { - var key = ((KeyCodecSingle) keyCodecBase).decode(dataDirectory); - codec.init(key); - } + public FloodgateDataCodec(FloodgateFormatCodec formatCodec, FloodgateConnectionCodec connectionCodec) { + this.formatCodec = formatCodec; + this.connectionCodec = connectionCodec; } - public static int version(String data) { - if (data.length() < HEADER.length) { - return -1; - } - - for (int i = 0; i < IDENTIFIER.length; i++) { - if (IDENTIFIER[i] != data.charAt(i)) { - return -1; - } - } - - return data.charAt(IDENTIFIER.length) - 0x3D; + public byte[] encode(FloodgateConnection connection) throws Exception { + return formatCodec.encode(connectionCodec.encode(connection)); } - public byte[] encode(ByteBuffer data) throws Exception { - var encryptedSections = codec.encode(data); - var encodedData = topping.encode(encryptedSections); - - return ByteBuffer.allocate(HEADER.length + encodedData.remaining()) - .put(HEADER) - .put(encodedData) - .array(); + public String encodeToString(FloodgateConnection connection) throws Exception { + return new String(encode(connection), StandardCharsets.UTF_8); } - public byte[] encodeFromString(String data) throws Exception { - return encode(ByteBuffer.wrap(data.getBytes(UTF_8))); - } - - public ByteBuffer decode(byte[] data) throws Exception { - checkHeader(data); - - int bufferLength = data.length - HEADER.length; - ByteBuffer buffer = ByteBuffer.wrap(data, HEADER.length, bufferLength); - - var encryptedSections = topping.decode(buffer); - return codec.decode(encryptedSections); - } - - public String decodeToString(byte[] data) throws Exception { - ByteBuffer decrypted = decode(data); - - byte[] decryptedBytes = new byte[decrypted.remaining()]; - decrypted.get(decryptedBytes); - - return new String(decryptedBytes, UTF_8); - } - - public ByteBuffer decodeFromString(String data) throws Exception { - return decode(data.getBytes(UTF_8)); - } - - /** - * Checks if the header is valid - * - * @param data the data to check - * @throws InvalidFormatException when the header is invalid - */ - public void checkHeader(byte[] data) throws InvalidFormatException { - if (data.length < HEADER.length) { - throw new InvalidFormatException( - "Data length is smaller then header." + - "Needed " + HEADER.length + ", got " + data.length - ); - } - - for (int i = 0; i < IDENTIFIER.length; i++) { - if (IDENTIFIER[i] != data[i]) { - String identifier = new String(IDENTIFIER, UTF_8); - String received = new String(data, 0, IDENTIFIER.length, UTF_8); - throw new InvalidFormatException( - "Expected identifier " + identifier + ", got " + received - ); - } - } + public FloodgateConnection decode(byte[] data) throws Exception { + return connectionCodec.decode(formatCodec.decode(data)); } } diff --git a/core/src/main/java/org/geysermc/floodgate/core/crypto/FloodgateFormatCodec.java b/core/src/main/java/org/geysermc/floodgate/core/crypto/FloodgateFormatCodec.java new file mode 100644 index 00000000..7828ec14 --- /dev/null +++ b/core/src/main/java/org/geysermc/floodgate/core/crypto/FloodgateFormatCodec.java @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Floodgate + */ + +package org.geysermc.floodgate.core.crypto; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import jakarta.inject.Named; +import jakarta.inject.Singleton; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.file.Path; +import java.util.Objects; +import org.geysermc.floodgate.core.crypto.exception.UnsupportedVersionException; +import org.geysermc.floodgate.core.crypto.topping.Topping; +import org.geysermc.floodgate.core.util.InvalidFormatException; + +@Singleton +public final class FloodgateFormatCodec { + public static final int VERSION = 2; + public static final byte[] IDENTIFIER = "^Floodgate^".getBytes(UTF_8); + public static final byte[] HEADER = (new String(IDENTIFIER, UTF_8) + (char) (VERSION + 0x3D)).getBytes(UTF_8); + + private final DataCodec codec; + + private final Topping topping; + + public FloodgateFormatCodec( + DataCodecType type, + Topping topping, + @Named("dataDirectory") Path dataDirectory + ) throws IOException { + Objects.requireNonNull(type); + this.codec = type.dataCodec(); + this.topping = topping; + + var keyCodecBase = type.keyCodec(); + if (type.asymmetrical()) { + var keyPair = ((KeyCodecPair) keyCodecBase).decode(dataDirectory); + ((DataCodecKeyPair) codec).init(keyPair); + } else { + var key = ((KeyCodecSingle) keyCodecBase).decode(dataDirectory); + codec.init(key); + } + } + + public static int version(String data) { + if (data.length() < HEADER.length) { + return -1; + } + + for (int i = 0; i < IDENTIFIER.length; i++) { + if (IDENTIFIER[i] != data.charAt(i)) { + return -1; + } + } + + return data.charAt(IDENTIFIER.length) - 0x3D; + } + + public byte[] encode(ByteBuffer data) throws Exception { + var encryptedSections = codec.encode(data); + var encodedData = topping.encode(encryptedSections); + + return ByteBuffer.allocate(HEADER.length + encodedData.remaining()) + .put(HEADER) + .put(encodedData) + .array(); + } + + public byte[] encodeFromString(String data) throws Exception { + return encode(ByteBuffer.wrap(data.getBytes(UTF_8))); + } + + public ByteBuffer decode(byte[] data) throws Exception { + validateHeader(data); + + int bufferLength = data.length - HEADER.length; + ByteBuffer buffer = ByteBuffer.wrap(data, HEADER.length, bufferLength); + + var encryptedSections = topping.decode(buffer); + return codec.decode(encryptedSections); + } + + public String decodeToString(byte[] data) throws Exception { + ByteBuffer decrypted = decode(data); + + byte[] decryptedBytes = new byte[decrypted.remaining()]; + decrypted.get(decryptedBytes); + + return new String(decryptedBytes, UTF_8); + } + + public ByteBuffer decodeFromString(String data) throws Exception { + return decode(data.getBytes(UTF_8)); + } + + /** + * Checks if the header is valid + * + * @param data the data to check + * @throws InvalidFormatException when the header is invalid + */ + public void validateHeader(byte[] data) throws InvalidFormatException, UnsupportedVersionException { + if (data.length < HEADER.length) { + throw new InvalidFormatException( + "Data length is smaller then header." + + "Needed " + HEADER.length + ", got " + data.length + ); + } + + for (int i = 0; i < IDENTIFIER.length; i++) { + if (IDENTIFIER[i] != data[i]) { + String identifier = new String(IDENTIFIER, UTF_8); + String received = new String(data, 0, IDENTIFIER.length, UTF_8); + throw new InvalidFormatException( + "Expected identifier " + identifier + ", got " + received + ); + } + } + + var receivedVersion = data[IDENTIFIER.length] - 0x3D; + + if (VERSION != receivedVersion) { + throw new UnsupportedVersionException(VERSION, receivedVersion); + } + } +} diff --git a/core/src/main/java/org/geysermc/floodgate/core/crypto/exception/UnsupportedVersionException.java b/core/src/main/java/org/geysermc/floodgate/core/crypto/exception/UnsupportedVersionException.java new file mode 100644 index 00000000..b34e565c --- /dev/null +++ b/core/src/main/java/org/geysermc/floodgate/core/crypto/exception/UnsupportedVersionException.java @@ -0,0 +1,7 @@ +package org.geysermc.floodgate.core.crypto.exception; + +public final class UnsupportedVersionException extends Exception { + public UnsupportedVersionException(int expected, int received) { + super("Expected Floodgate data version " + expected + ", received version " + received); + } +} diff --git a/core/src/main/java/org/geysermc/floodgate/core/link/PlayerLinkJdbc.java b/core/src/main/java/org/geysermc/floodgate/core/link/PlayerLinkJdbc.java index 5965f0be..33675ade 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/link/PlayerLinkJdbc.java +++ b/core/src/main/java/org/geysermc/floodgate/core/link/PlayerLinkJdbc.java @@ -41,6 +41,8 @@ import org.geysermc.floodgate.core.database.PlayerLinkRepository; import org.geysermc.floodgate.core.database.entity.LinkRequest; import org.geysermc.floodgate.core.database.entity.LinkedPlayer; +@Requires(property = "config.database.enabled", value = "true") +@Requires(property = "config.playerLink.enabled", value = "true") @Requires(property = "config.playerLink.enableOwnLinking", value = "true") @Replaces(DisabledPlayerLink.class) @Named("localLinking") diff --git a/core/src/main/java/org/geysermc/floodgate/core/module/CommonModule.java b/core/src/main/java/org/geysermc/floodgate/core/module/CommonModule.java index 593f0559..93e6aacf 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/module/CommonModule.java +++ b/core/src/main/java/org/geysermc/floodgate/core/module/CommonModule.java @@ -31,7 +31,6 @@ import io.micronaut.context.annotation.Factory; import io.netty.util.AttributeKey; import jakarta.inject.Named; import jakarta.inject.Singleton; -import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.concurrent.ExecutorService; @@ -42,7 +41,6 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.geysermc.api.connection.Connection; import org.geysermc.floodgate.core.crypto.DataCodecType; -import org.geysermc.floodgate.core.crypto.FloodgateDataCodec; import org.geysermc.floodgate.core.crypto.topping.Base64Topping; import org.geysermc.floodgate.core.crypto.topping.Topping; import org.geysermc.floodgate.core.util.Constants; @@ -91,24 +89,6 @@ public class CommonModule { return GlobalBeanCache.cacheIfAbsent("topping", Base64Topping::new); } - @Bean - @BootstrapContextCompatible - @Singleton - public FloodgateDataCodec dataCodec( - DataCodecType type, - Topping topping, - @Named("dataDirectory") Path dataDirectory - ) { - //todo find a way to not use bootstrap context, yuk - return GlobalBeanCache.cacheIfAbsent("dataCodec", () -> { - try { - return new FloodgateDataCodec(type, topping, dataDirectory); - } catch (IOException e) { - throw new RuntimeException(e); - } - }); - } - @Bean @Singleton @Named("gitBranch") diff --git a/core/src/main/java/org/geysermc/floodgate/core/platform/command/CommandUtil.java b/core/src/main/java/org/geysermc/floodgate/core/platform/command/CommandUtil.java index 8fcdc391..c8903dbc 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/platform/command/CommandUtil.java +++ b/core/src/main/java/org/geysermc/floodgate/core/platform/command/CommandUtil.java @@ -38,8 +38,8 @@ import lombok.RequiredArgsConstructor; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.api.GeyserApiBase; -import org.geysermc.floodgate.core.connection.UserAudience; import org.geysermc.floodgate.core.connection.audience.ProfileAudience; +import org.geysermc.floodgate.core.connection.audience.UserAudience; import org.geysermc.floodgate.core.platform.util.PlayerType; import org.geysermc.floodgate.core.util.LanguageManager; import org.geysermc.floodgate.core.util.Utils; diff --git a/core/src/main/java/org/geysermc/floodgate/core/platform/command/FloodgateCommand.java b/core/src/main/java/org/geysermc/floodgate/core/platform/command/FloodgateCommand.java index 02b9401b..fce04e59 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/platform/command/FloodgateCommand.java +++ b/core/src/main/java/org/geysermc/floodgate/core/platform/command/FloodgateCommand.java @@ -29,7 +29,7 @@ import cloud.commandframework.Command; import cloud.commandframework.CommandManager; import cloud.commandframework.context.CommandContext; import org.geysermc.floodgate.core.config.FloodgateConfig; -import org.geysermc.floodgate.core.connection.UserAudience; +import org.geysermc.floodgate.core.connection.audience.UserAudience; /** The base class for every Floodgate command. */ public interface FloodgateCommand { diff --git a/core/src/main/java/org/geysermc/floodgate/core/platform/command/FloodgateSubCommand.java b/core/src/main/java/org/geysermc/floodgate/core/platform/command/FloodgateSubCommand.java index bfe1f728..78110507 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/platform/command/FloodgateSubCommand.java +++ b/core/src/main/java/org/geysermc/floodgate/core/platform/command/FloodgateSubCommand.java @@ -27,7 +27,7 @@ package org.geysermc.floodgate.core.platform.command; import cloud.commandframework.context.CommandContext; import org.geysermc.floodgate.core.command.util.Permission; -import org.geysermc.floodgate.core.connection.UserAudience; +import org.geysermc.floodgate.core.connection.audience.UserAudience; public abstract class FloodgateSubCommand { public abstract Class parent(); diff --git a/core/src/main/java/org/geysermc/floodgate/core/register/CommandRegister.java b/core/src/main/java/org/geysermc/floodgate/core/register/CommandRegister.java index 7eda86a0..e03c10f8 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/register/CommandRegister.java +++ b/core/src/main/java/org/geysermc/floodgate/core/register/CommandRegister.java @@ -30,7 +30,7 @@ import jakarta.inject.Inject; import jakarta.inject.Singleton; import java.util.Set; import org.geysermc.floodgate.core.config.FloodgateConfig; -import org.geysermc.floodgate.core.connection.UserAudience; +import org.geysermc.floodgate.core.connection.audience.UserAudience; import org.geysermc.floodgate.core.platform.command.FloodgateCommand; /** diff --git a/core/src/main/java/org/geysermc/floodgate/core/util/InvalidFormatException.java b/core/src/main/java/org/geysermc/floodgate/core/util/InvalidFormatException.java index c066a877..ee3fb62d 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/util/InvalidFormatException.java +++ b/core/src/main/java/org/geysermc/floodgate/core/util/InvalidFormatException.java @@ -25,7 +25,7 @@ package org.geysermc.floodgate.core.util; -public class InvalidFormatException extends Exception { +public final class InvalidFormatException extends Exception { public InvalidFormatException(String message) { super(message); } diff --git a/core/src/test/java/org/geysermc/floodgate/core/crypto/FloodgateDataCodecTest.java b/core/src/test/java/org/geysermc/floodgate/core/crypto/FloodgateFormatCodecTest.java similarity index 80% rename from core/src/test/java/org/geysermc/floodgate/core/crypto/FloodgateDataCodecTest.java rename to core/src/test/java/org/geysermc/floodgate/core/crypto/FloodgateFormatCodecTest.java index 63943b0b..42acdfed 100644 --- a/core/src/test/java/org/geysermc/floodgate/core/crypto/FloodgateDataCodecTest.java +++ b/core/src/test/java/org/geysermc/floodgate/core/crypto/FloodgateFormatCodecTest.java @@ -25,7 +25,7 @@ package org.geysermc.floodgate.core.crypto; -import static org.geysermc.floodgate.core.crypto.FloodgateDataCodec.VERSION; +import static org.geysermc.floodgate.core.crypto.FloodgateFormatCodec.VERSION; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -35,6 +35,7 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.nio.file.Path; +import org.geysermc.floodgate.core.crypto.exception.UnsupportedVersionException; import org.geysermc.floodgate.core.crypto.topping.Base64Topping; import org.geysermc.floodgate.core.util.InvalidFormatException; import org.junit.jupiter.api.Test; @@ -43,7 +44,7 @@ import org.junit.jupiter.params.aggregator.ArgumentsAccessor; import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.ValueSource; -final class FloodgateDataCodecTest { +final class FloodgateFormatCodecTest { @ParameterizedTest @CsvSource({ "^Floodgate^, -1", @@ -53,7 +54,7 @@ final class FloodgateDataCodecTest { "^Floodgate^A, 4", }) void version(ArgumentsAccessor arguments) { - assertEquals(arguments.getInteger(1), FloodgateDataCodec.version(arguments.getString(0))); + assertEquals(arguments.getInteger(1), FloodgateFormatCodec.version(arguments.getString(0))); } @Test @@ -63,7 +64,7 @@ final class FloodgateDataCodecTest { @Test void createWithSymmetricalKey() { - assertDoesNotThrow(() -> new FloodgateDataCodec( + assertDoesNotThrow(() -> new FloodgateFormatCodec( DataCodecType.AES, new Base64Topping(), Path.of("src/test/resources/crypto") @@ -115,31 +116,42 @@ final class FloodgateDataCodecTest { assertEquals(payloadExpected, payload); } - @ParameterizedTest - @ValueSource(strings = { - "^Floodgate^" + (VERSION - 1), - "^Floodgate^" + VERSION, - "^Floodgate^" + (VERSION + 1) - }) - void headerValid(String value) throws IOException { - var codec = createFloodgateDataCodec(); - assertDoesNotThrow(() -> codec.checkHeader(value.getBytes(StandardCharsets.UTF_8))); - } - @ParameterizedTest @ValueSource(strings = { "^Floodgate^", "^Flootgate^=" }) - void headerInvalid(String value) throws IOException { + void headerInvalidFormat(String content) throws IOException { var codec = createFloodgateDataCodec(); + assertThrowsExactly( InvalidFormatException.class, - () -> codec.checkHeader(value.getBytes(StandardCharsets.UTF_8)) + () -> codec.validateHeader(content.getBytes(StandardCharsets.UTF_8)) ); } - private FloodgateDataCodec createFloodgateDataCodec() throws IOException { - return new FloodgateDataCodec(DataCodecType.ED25519, new Base64Topping(), Path.of("src/test/resources/crypto")); + @ParameterizedTest + @CsvSource({ + (VERSION - 1) + ", false", + VERSION + ", true", + (VERSION + 1) + ", false" + }) + void headerVersionValidation(ArgumentsAccessor arguments) throws IOException { + var codec = createFloodgateDataCodec(); + + var version = arguments.getInteger(0); + var content = ("^Floodgate^" + (char) (version + 0x3D)).getBytes(StandardCharsets.UTF_8); + + var valid = arguments.getBoolean(1); + + if (valid) { + assertDoesNotThrow(() -> codec.validateHeader(content)); + } else { + assertThrowsExactly(UnsupportedVersionException.class, () -> codec.validateHeader(content)); + } + } + + private FloodgateFormatCodec createFloodgateDataCodec() throws IOException { + return new FloodgateFormatCodec(DataCodecType.ED25519, new Base64Topping(), Path.of("src/test/resources/crypto")); } } diff --git a/gradle.properties b/gradle.properties index 37dc533e..d355fc77 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,4 +4,4 @@ org.gradle.parallel=true systemProp.org.gradle.unsafe.kotlin.assignment=true version=2.2.2-SNAPSHOT -micronautVersion=4.0.3 \ No newline at end of file +micronautVersion=4.1.3 \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 81ea1b5e..39aaf12a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] # parent -micronaut-gradle = "4.0.2" +micronaut-gradle = "4.1.1" lombok = "8.0.1" # api @@ -29,8 +29,8 @@ authlib = "1.5.21" velocity = "3.1.1" # buildSrc -indra = "3.0.1" -shadow = "7.1.1" +indra = "3.1.3" +shadow = "8.1.1" gradle-idea-ext = "1.1.7" checkerframework = "3.19.0" @@ -96,7 +96,7 @@ checker-qual = { module = "org.checkerframework:checker-qual", version.ref = "ch # plugins indra-common = { module = "net.kyori:indra-common", version.ref = "indra" } indra-git = { module = "net.kyori:indra-git", version.ref = "indra" } -shadow = { module = "gradle.plugin.com.github.johnrengelman:shadow", version.ref = "shadow" } +shadow = { module = "com.github.johnrengelman:shadow", version.ref = "shadow" } gradle-idea-ext = { module = "gradle.plugin.org.jetbrains.gradle.plugin.idea-ext:gradle-idea-ext", version.ref = "gradle-idea-ext" } [plugins] diff --git a/spigot/base/src/main/java/org/geysermc/floodgate/spigot/SpigotPlatform.java b/spigot/base/src/main/java/org/geysermc/floodgate/spigot/SpigotPlatform.java index 1564b3b5..b1521851 100644 --- a/spigot/base/src/main/java/org/geysermc/floodgate/spigot/SpigotPlatform.java +++ b/spigot/base/src/main/java/org/geysermc/floodgate/spigot/SpigotPlatform.java @@ -69,7 +69,7 @@ public class SpigotPlatform extends FloodgatePlatform { } @Override - protected boolean isProxy() { + public boolean isProxy() { return false; } } diff --git a/spigot/base/src/main/java/org/geysermc/floodgate/spigot/command/SpigotCommandManager.java b/spigot/base/src/main/java/org/geysermc/floodgate/spigot/command/SpigotCommandManager.java index 7f698f14..5255993f 100644 --- a/spigot/base/src/main/java/org/geysermc/floodgate/spigot/command/SpigotCommandManager.java +++ b/spigot/base/src/main/java/org/geysermc/floodgate/spigot/command/SpigotCommandManager.java @@ -39,8 +39,8 @@ import org.bukkit.permissions.PermissionDefault; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; import org.geysermc.floodgate.core.command.util.Permission; -import org.geysermc.floodgate.core.connection.FloodgateCommandPreprocessor; -import org.geysermc.floodgate.core.connection.UserAudience; +import org.geysermc.floodgate.core.connection.audience.FloodgateCommandPreprocessor; +import org.geysermc.floodgate.core.connection.audience.UserAudience; import org.geysermc.floodgate.core.platform.command.CommandUtil; @Factory diff --git a/spigot/base/src/main/java/org/geysermc/floodgate/spigot/util/SpigotCommandUtil.java b/spigot/base/src/main/java/org/geysermc/floodgate/spigot/util/SpigotCommandUtil.java index d32bb0a7..17219b3f 100644 --- a/spigot/base/src/main/java/org/geysermc/floodgate/spigot/util/SpigotCommandUtil.java +++ b/spigot/base/src/main/java/org/geysermc/floodgate/spigot/util/SpigotCommandUtil.java @@ -34,9 +34,9 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.api.GeyserApiBase; -import org.geysermc.floodgate.core.connection.UserAudience; -import org.geysermc.floodgate.core.connection.UserAudience.ConsoleAudience; -import org.geysermc.floodgate.core.connection.UserAudience.PlayerAudience; +import org.geysermc.floodgate.core.connection.audience.UserAudience; +import org.geysermc.floodgate.core.connection.audience.UserAudience.ConsoleAudience; +import org.geysermc.floodgate.core.connection.audience.UserAudience.PlayerAudience; import org.geysermc.floodgate.core.platform.command.CommandUtil; import org.geysermc.floodgate.core.util.LanguageManager; diff --git a/velocity/base/src/main/java/org/geysermc/floodgate/velocity/VelocityPlatform.java b/velocity/base/src/main/java/org/geysermc/floodgate/velocity/VelocityPlatform.java index 09b0dbeb..a2f82ad7 100644 --- a/velocity/base/src/main/java/org/geysermc/floodgate/velocity/VelocityPlatform.java +++ b/velocity/base/src/main/java/org/geysermc/floodgate/velocity/VelocityPlatform.java @@ -63,7 +63,7 @@ public class VelocityPlatform extends FloodgatePlatform { } @Override - protected boolean isProxy() { + public boolean isProxy() { return true; } } diff --git a/velocity/base/src/main/java/org/geysermc/floodgate/velocity/module/VelocityPlatformModule.java b/velocity/base/src/main/java/org/geysermc/floodgate/velocity/module/VelocityPlatformModule.java index 0374ee80..20a2f6e5 100644 --- a/velocity/base/src/main/java/org/geysermc/floodgate/velocity/module/VelocityPlatformModule.java +++ b/velocity/base/src/main/java/org/geysermc/floodgate/velocity/module/VelocityPlatformModule.java @@ -35,8 +35,8 @@ import io.micronaut.context.annotation.Bean; import io.micronaut.context.annotation.Factory; import jakarta.inject.Named; import jakarta.inject.Singleton; -import org.geysermc.floodgate.core.connection.FloodgateCommandPreprocessor; -import org.geysermc.floodgate.core.connection.UserAudience; +import org.geysermc.floodgate.core.connection.audience.FloodgateCommandPreprocessor; +import org.geysermc.floodgate.core.connection.audience.UserAudience; import org.geysermc.floodgate.core.platform.command.CommandUtil; @Factory diff --git a/velocity/base/src/main/java/org/geysermc/floodgate/velocity/util/VelocityCommandUtil.java b/velocity/base/src/main/java/org/geysermc/floodgate/velocity/util/VelocityCommandUtil.java index 3df57281..54bb6482 100644 --- a/velocity/base/src/main/java/org/geysermc/floodgate/velocity/util/VelocityCommandUtil.java +++ b/velocity/base/src/main/java/org/geysermc/floodgate/velocity/util/VelocityCommandUtil.java @@ -36,9 +36,9 @@ import java.util.UUID; import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.api.GeyserApiBase; -import org.geysermc.floodgate.core.connection.UserAudience; -import org.geysermc.floodgate.core.connection.UserAudience.ConsoleAudience; -import org.geysermc.floodgate.core.connection.UserAudience.PlayerAudience; +import org.geysermc.floodgate.core.connection.audience.UserAudience; +import org.geysermc.floodgate.core.connection.audience.UserAudience.ConsoleAudience; +import org.geysermc.floodgate.core.connection.audience.UserAudience.PlayerAudience; import org.geysermc.floodgate.core.platform.command.CommandUtil; import org.geysermc.floodgate.core.util.LanguageManager; import org.geysermc.floodgate.core.util.Utils;