Updated Gradle to 8.3 and made Geyser work with latest Floodgate

This commit is contained in:
Tim203 2023-09-30 19:41:35 +02:00
parent a4ee73d1ef
commit a894ce9824
No known key found for this signature in database
52 changed files with 206 additions and 1656 deletions

View File

@ -23,11 +23,7 @@
* @link https://github.com/GeyserMC/Geyser
*/
<<<<<<<< HEAD:core/src/main/java/org/geysermc/geyser/util/PlatformType.java
package org.geysermc.geyser.util;
========
package org.geysermc.geyser.api.bedrock.camera;
>>>>>>>> origin/master:api/src/main/java/org/geysermc/geyser/api/bedrock/camera/CameraShake.java
public enum CameraShake {
POSITIONAL,

View File

@ -31,8 +31,6 @@ import net.md_5.bungee.api.config.ListenerInfo;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.protocol.ProtocolConstants;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.floodgate.bungee.BungeePlatform;
import org.geysermc.floodgate.bungee.pluginmessage.BungeeSkinApplier;
import org.geysermc.floodgate.core.skin.SkinApplier;
import org.geysermc.geyser.api.util.PlatformType;
import org.geysermc.geyser.GeyserBootstrap;
@ -43,8 +41,6 @@ import org.geysermc.geyser.api.network.AuthType;
import org.geysermc.geyser.command.GeyserCommandManager;
import org.geysermc.geyser.configuration.GeyserConfiguration;
import org.geysermc.geyser.dump.BootstrapDumpInfo;
import org.geysermc.geyser.hybrid.HybridProvider;
import org.geysermc.geyser.hybrid.ProxyHybridProvider;
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
import org.geysermc.geyser.platform.bungeecord.command.GeyserBungeeCommandExecutor;
@ -280,11 +276,6 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
.findFirst();
}
@Override
public HybridProvider createHybridProvider(GeyserImpl geyser) {
return new ProxyHybridProvider(geyser);
}
@Override
public SkinApplier createSkinApplier() {
// new BungeePlatform(this); // TODO hack to ensure ReflectionUtils prefix is applied and I don't forget about dealing with it

View File

@ -54,7 +54,6 @@ import org.geysermc.geyser.platform.fabric.command.GeyserFabricCommandExecutor;
import org.geysermc.geyser.platform.fabric.world.GeyserFabricWorldManager;
import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.util.FileUtils;
import org.geysermc.geyser.util.PlatformType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

View File

@ -53,8 +53,6 @@ import org.geysermc.geyser.api.extension.Extension;
import org.geysermc.geyser.command.GeyserCommandManager;
import org.geysermc.geyser.configuration.GeyserConfiguration;
import org.geysermc.geyser.dump.BootstrapDumpInfo;
import org.geysermc.geyser.hybrid.HybridProvider;
import org.geysermc.geyser.hybrid.IntegratedHybridProvider;
import org.geysermc.geyser.level.WorldManager;
import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
@ -414,11 +412,6 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
return this.geyserInjector.getServerSocketAddress();
}
@Override
public HybridProvider createHybridProvider(GeyserImpl geyser) {
return new IntegratedHybridProvider(geyser);
}
@Override
public SkinApplier createSkinApplier() {
// return new SpigotSkinApplier(new SpigotVersionSpecificMethods(this), this);

View File

@ -30,7 +30,7 @@ import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.geysermc.floodgate.spigot.util.ClassNames;
import org.geysermc.geyser.hybrid.IntegratedHybridProvider;
import org.geysermc.geyser.floodgate.IntegratedFloodgateProvider;
import org.geysermc.geyser.session.GeyserSession;
import javax.annotation.Nonnull;
@ -42,7 +42,7 @@ public final class SpigotHybridChannelHandler extends ChannelInboundHandlerAdapt
@Override
public void channelRead(@Nonnull ChannelHandlerContext ctx, @Nonnull Object packet) throws Exception {
GeyserSession session = ctx.channel().attr(IntegratedHybridProvider.SESSION_KEY).get();
GeyserSession session = ctx.channel().attr(IntegratedFloodgateProvider.SESSION_KEY).get();
// TODO generify this code within Floodgate
if (ClassNames.LOGIN_START_PACKET.isInstance(packet)) {
Object networkManager = ctx.channel().pipeline().get("packet_handler");

View File

@ -296,7 +296,7 @@ public class GeyserStandaloneGUI {
for (GeyserSession player : GeyserImpl.getInstance().getSessionManager().getSessions().values()) {
Vector<String> row = new Vector<>();
row.add(player.socketAddress().getHostName());
row.add(player.getUpstream().getAddress().getHostName());
row.add(player.getPlayerEntity().getUsername());
playerTableModel.addRow(row);

View File

@ -2,15 +2,21 @@ dependencies {
annotationProcessor(libs.velocity.api)
implementation(libs.floodgate.velocity)
api(projects.core)
compileOnlyApi(libs.velocity.api) {
exclude(module = "org.yaml:snakeyaml")
}
}
platformRelocate("com.fasterxml.jackson")
platformRelocate("it.unimi.dsi.fastutil")
platformRelocate("net.kyori.adventure.text.serializer.gson.legacyimpl")
platformRelocate("org.yaml.snakeyaml")
platformRelocate("org.bstats") //todo
exclude("com.google.*:*")
// Needed because Velocity provides every dependency except netty-resolver-dns
// Needed because Velocity provides every dependency except netty-resolver-dns
exclude("io.netty:netty-transport-native-epoll:*")
exclude("io.netty:netty-transport-native-unix-common:*")
exclude("io.netty:netty-transport-native-kqueue:*")
@ -24,16 +30,13 @@ exclude("io.netty:netty-codec-haproxy:*")
exclude("org.slf4j:*")
exclude("org.ow2.asm:*")
// Exclude all Kyori dependencies except the legacy NBT serializer
// Exclude all Kyori dependencies except the legacy NBT serializer
exclude("net.kyori:adventure-api:*")
exclude("net.kyori:examination-api:*")
exclude("net.kyori:examination-string:*")
exclude("net.kyori:adventure-text-serializer-gson:*")
exclude("net.kyori:adventure-text-serializer-legacy:*")
exclude("net.kyori:adventure-nbt:*")
// These dependencies are already present on the platform
provided(libs.velocity.api)
application {
mainClass.set("org.geysermc.geyser.platform.velocity.GeyserVelocityMain")

View File

@ -38,6 +38,7 @@ import com.velocitypowered.api.proxy.ProxyServer;
import lombok.Getter;
import net.kyori.adventure.util.Codec;
import org.geysermc.floodgate.core.FloodgatePlatform;
import org.geysermc.floodgate.velocity.VelocityPlatform;
import org.geysermc.geyser.api.util.PlatformType;
import org.geysermc.geyser.GeyserBootstrap;
import org.geysermc.geyser.GeyserImpl;
@ -50,7 +51,7 @@ import org.geysermc.geyser.dump.BootstrapDumpInfo;
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
import org.geysermc.geyser.platform.velocity.command.GeyserVelocityCommandExecutor;
import org.geysermc.geyser.platform.velocity.floodgate.FloodgateVelocityPlatform;
import org.geysermc.geyser.platform.velocity.floodgate.FloodgateModule;
import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.util.FileUtils;
import org.jetbrains.annotations.NotNull;
@ -122,7 +123,7 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
FloodgatePlatform platform = null;
if (geyserConfig.getRemote().authType() == AuthType.FLOODGATE) {
platform = guice.getInstance(FloodgateVelocityPlatform.class);
platform = guice.createChildInjector(new FloodgateModule(configFolder)).getInstance(VelocityPlatform.class);
}
this.geyser = GeyserImpl.load(PlatformType.VELOCITY, this, platform);

View File

@ -25,21 +25,20 @@
package org.geysermc.geyser.platform.velocity.floodgate;
import com.google.inject.AbstractModule;
import java.nio.file.Path;
import org.geysermc.floodgate.isolation.library.LibraryManager;
import org.geysermc.floodgate.velocity.VelocityPlatform;
public class FloodgateVelocityPlatform extends VelocityPlatform {
public FloodgateVelocityPlatform(LibraryManager manager) {
super(manager);
public class FloodgateModule extends AbstractModule {
private final Path dataDirectory;
public FloodgateModule(Path dataDirectory) {
this.dataDirectory = dataDirectory;
}
// @Override
// protected List<Module> loadStageModules() {
// // Geyser being a dumb dumb
// super.dataDirectory = Paths.get("plugins/" + GeyserImpl.NAME + "-Velocity/");
//
// var loaded = super.loadStageModules();
// loaded.add(new GeyserLoadStage());
// return loaded;
// }
@Override
protected void configure() {
var libsDirectory = dataDirectory.resolve("libs");
bind(LibraryManager.class).toInstance(new LibraryManager(getClass().getClassLoader(), libsDirectory, true));
}
}

View File

@ -8,8 +8,8 @@ repositories {
}
dependencies {
implementation("net.kyori", "indra-common", "3.1.1")
implementation("com.github.johnrengelman", "shadow", "7.1.3-SNAPSHOT")
implementation("net.kyori", "indra-common", "3.1.3")
implementation("com.github.johnrengelman", "shadow", "8.1.1")
// Within the gradle plugin classpath, there is a version conflict between loom and some other
// plugin for databind. This fixes it: minimum 2.13.2 is required by loom.

View File

@ -1,7 +1,7 @@
plugins {
`java-library`
id("geyser.build-logic")
id("io.freefair.lombok") version "6.3.0" apply false
id("io.freefair.lombok") version "8.3" apply false
}
allprojects {

View File

@ -1,14 +0,0 @@
plugins {
id("geyser.publish-conventions")
}
dependencies {
api(libs.cumulus)
api(libs.gson)
}
indra {
javaVersions {
target(8)
}
}

View File

@ -1,124 +0,0 @@
/*
* Copyright (c) 2019-2022 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/Geyser
*/
package org.geysermc.floodgate.crypto;
import lombok.RequiredArgsConstructor;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.security.Key;
import java.security.SecureRandom;
@RequiredArgsConstructor
public final class AesCipher implements FloodgateCipher {
public static final int IV_LENGTH = 12;
private static final int TAG_BIT_LENGTH = 128;
private static final String CIPHER_NAME = "AES/GCM/NoPadding";
private final SecureRandom secureRandom = new SecureRandom();
private final Topping topping;
private SecretKey secretKey;
public void init(Key key) {
if (!"AES".equals(key.getAlgorithm())) {
throw new RuntimeException(
"Algorithm was expected to be AES, but got " + key.getAlgorithm()
);
}
secretKey = (SecretKey) key;
}
public byte[] encrypt(byte[] data) throws Exception {
Cipher cipher = Cipher.getInstance(CIPHER_NAME);
byte[] iv = new byte[IV_LENGTH];
secureRandom.nextBytes(iv);
GCMParameterSpec spec = new GCMParameterSpec(TAG_BIT_LENGTH, iv);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, spec);
byte[] cipherText = cipher.doFinal(data);
if (topping != null) {
iv = topping.encode(iv);
cipherText = topping.encode(cipherText);
}
return ByteBuffer.allocate(HEADER.length + iv.length + cipherText.length + 1)
.put(HEADER)
.put(iv)
.put((byte) 0x21)
.put(cipherText)
.array();
}
public byte[] decrypt(byte[] cipherTextWithIv) throws Exception {
checkHeader(cipherTextWithIv);
Cipher cipher = Cipher.getInstance(CIPHER_NAME);
int bufferLength = cipherTextWithIv.length - HEADER.length;
ByteBuffer buffer = ByteBuffer.wrap(cipherTextWithIv, HEADER.length, bufferLength);
int ivLength = IV_LENGTH;
if (topping != null) {
int mark = buffer.position();
// we need the first index, the second is for the actual data
boolean found = false;
while (buffer.hasRemaining() && !found) {
if (buffer.get() == 0x21) {
found = true;
}
}
ivLength = buffer.position() - mark - 1; // don't include the splitter itself
// don't remove this cast, it'll cause problems if you remove it
((Buffer) buffer).position(mark); // reset to the pre-while index
}
byte[] iv = new byte[ivLength];
buffer.get(iv);
// don't remove this cast, it'll cause problems if you remove it
((Buffer) buffer).position(buffer.position() + 1); // skip splitter
byte[] cipherText = new byte[buffer.remaining()];
buffer.get(cipherText);
if (topping != null) {
iv = topping.decode(iv);
cipherText = topping.decode(cipherText);
}
GCMParameterSpec spec = new GCMParameterSpec(TAG_BIT_LENGTH, iv);
cipher.init(Cipher.DECRYPT_MODE, secretKey, spec);
return cipher.doFinal(cipherText);
}
}

View File

@ -1,73 +0,0 @@
/*
* Copyright (c) 2019-2022 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/Geyser
*/
package org.geysermc.floodgate.crypto;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
public final class AesKeyProducer implements KeyProducer {
public static int KEY_SIZE = 128;
@Override
public SecretKey produce() {
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(KEY_SIZE, secureRandom());
return keyGenerator.generateKey();
} catch (Exception exception) {
throw new RuntimeException(exception);
}
}
@Override
public SecretKey produceFrom(byte[] keyFileData) {
try {
return new SecretKeySpec(keyFileData, "AES");
} catch (Exception exception) {
throw new RuntimeException(exception);
}
}
private SecureRandom secureRandom() throws NoSuchAlgorithmException {
// use Windows-PRNG for windows (default impl is SHA1PRNG)
if (System.getProperty("os.name").startsWith("Windows")) {
return SecureRandom.getInstance("Windows-PRNG");
} else {
try {
// NativePRNG (which should be the default on unix-systems) can still block your
// system. Even though it isn't as bad as NativePRNGBlocking, we still try to
// prevent that if possible
return SecureRandom.getInstance("NativePRNGNonBlocking");
} catch (NoSuchAlgorithmException ignored) {
// at this point we just have to go with the default impl even if it blocks
return new SecureRandom();
}
}
}
}

View File

@ -1,145 +0,0 @@
/*
* Copyright (c) 2019-2022 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/Geyser
*/
package org.geysermc.floodgate.crypto;
import org.geysermc.floodgate.util.InvalidFormatException;
import java.security.Key;
import static java.nio.charset.StandardCharsets.UTF_8;
/**
* Responsible for both encrypting and decrypting data
*/
public interface FloodgateCipher {
int VERSION = 0;
byte[] IDENTIFIER = "^Floodgate^".getBytes(UTF_8);
byte[] HEADER = (new String(IDENTIFIER, UTF_8) + (char) (VERSION + 0x3E)).getBytes(UTF_8);
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) - 0x3E;
}
/**
* Initializes the instance by giving it the key it needs to encrypt or decrypt data
*
* @param key the key used to encrypt and decrypt data
*/
void init(Key key);
/**
* Encrypts the given data using the Key provided in {@link #init(Key)}
*
* @param data the data to encrypt
* @return the encrypted data
* @throws Exception when the encryption failed
*/
byte[] encrypt(byte[] data) throws Exception;
/**
* Encrypts data from a String.<br> This method internally calls {@link #encrypt(byte[])}
*
* @param data the data to encrypt
* @return the encrypted data
* @throws Exception when the encryption failed
*/
default byte[] encryptFromString(String data) throws Exception {
return encrypt(data.getBytes(UTF_8));
}
/**
* Decrypts the given data using the Key provided in {@link #init(Key)}
*
* @param data the data to decrypt
* @return the decrypted data
* @throws Exception when the decrypting failed
*/
byte[] decrypt(byte[] data) throws Exception;
/**
* Decrypts a byte[] and turn it into a String.<br> This method internally calls {@link
* #decrypt(byte[])} and converts the returned byte[] into a String.
*
* @param data the data to encrypt
* @return the decrypted data in a UTF-8 String
* @throws Exception when the decrypting failed
*/
default String decryptToString(byte[] data) throws Exception {
byte[] decrypted = decrypt(data);
if (decrypted == null) {
return null;
}
return new String(decrypted, UTF_8);
}
/**
* Decrypts a String.<br> This method internally calls {@link #decrypt(byte[])} by converting
* the UTF-8 String into a byte[]
*
* @param data the data to decrypt
* @return the decrypted data in a byte[]
* @throws Exception when the decrypting failed
*/
default byte[] decryptFromString(String data) throws Exception {
return decrypt(data.getBytes(UTF_8));
}
/**
* Checks if the header is valid. This method will throw an InvalidFormatException when the
* header is invalid.
*
* @param data the data to check
* @throws InvalidFormatException when the header is invalid
*/
default 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
);
}
}
}
}

View File

@ -1,40 +0,0 @@
/*
* Copyright (c) 2019-2022 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/Geyser
*/
package org.geysermc.floodgate.crypto;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.Key;
public interface KeyProducer {
Key produce();
Key produceFrom(byte[] keyFileData);
default Key produceFrom(Path keyFileLocation) throws IOException {
return produceFrom(Files.readAllBytes(keyFileLocation));
}
}

View File

@ -1,31 +0,0 @@
/*
* Copyright (c) 2019-2022 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/Geyser
*/
package org.geysermc.floodgate.crypto;
public interface Topping {
byte[] encode(byte[] data);
byte[] decode(byte[] data);
}

View File

@ -1,127 +0,0 @@
/*
* Copyright (c) 2019-2022 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/Geyser
*/
package org.geysermc.floodgate.news;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import org.geysermc.floodgate.news.data.ItemData;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public final class NewsItem {
private final int id;
private final boolean active;
private final NewsType type;
private final ItemData data;
private final String message;
private final Set<NewsItemAction> actions;
private final String url;
private NewsItem(
int id, boolean active, NewsType type, ItemData data,
String message, Set<NewsItemAction> actions, String url) {
this.id = id;
this.active = active;
this.type = type;
this.data = data;
this.message = message;
this.actions = Collections.unmodifiableSet(actions);
this.url = url;
}
public static NewsItem readItem(JsonObject newsItem) {
NewsType newsType = NewsType.getByName(newsItem.get("type").getAsString());
if (newsType == null) {
return null;
}
JsonObject messageObject = newsItem.getAsJsonObject("message");
NewsItemMessage itemMessage = NewsItemMessage.getById(messageObject.get("id").getAsInt());
String message = "Received an unknown news message type. Please update";
if (itemMessage != null) {
message = itemMessage.getFormattedMessage(messageObject.getAsJsonArray("args"));
}
Set<NewsItemAction> actions = new HashSet<>();
for (JsonElement actionElement : newsItem.getAsJsonArray("actions")) {
NewsItemAction action = NewsItemAction.getByName(actionElement.getAsString());
if (action != null) {
actions.add(action);
}
}
return new NewsItem(
newsItem.get("id").getAsInt(),
newsItem.get("active").getAsBoolean(),
newsType,
newsType.read(newsItem.getAsJsonObject("data")),
message,
actions,
newsItem.get("url").getAsString()
);
}
public int getId() {
return id;
}
public boolean isActive() {
return active;
}
public NewsType getType() {
return type;
}
public ItemData getData() {
return data;
}
@SuppressWarnings("unchecked")
public <T extends ItemData> T getDataAs(Class<T> type) {
return (T) data;
}
public String getRawMessage() {
return message;
}
public String getMessage() {
return message + " See " + getUrl() + " for more information.";
}
public Set<NewsItemAction> getActions() {
return actions;
}
public String getUrl() {
return url;
}
}

View File

@ -1,44 +0,0 @@
/*
* Copyright (c) 2019-2022 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/Geyser
*/
package org.geysermc.floodgate.news;
public enum NewsItemAction {
ON_SERVER_STARTED,
ON_OPERATOR_JOIN,
BROADCAST_TO_CONSOLE,
BROADCAST_TO_OPERATORS;
private static final NewsItemAction[] VALUES = values();
public static NewsItemAction getByName(String actionName) {
for (NewsItemAction type : VALUES) {
if (type.name().equalsIgnoreCase(actionName)) {
return type;
}
}
return null;
}
}

View File

@ -1,89 +0,0 @@
/*
* Copyright (c) 2019-2022 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/Geyser
*/
package org.geysermc.floodgate.news;
import com.google.gson.JsonArray;
// {} is used for things that have to be filled in by the server,
// {@} is for things that have to be filled in by us
public enum NewsItemMessage {
UPDATE_AVAILABLE("There is an update available for {}. The newest version is: {}"),
UPDATE_RECOMMENDED(UPDATE_AVAILABLE + ". Your version is quite old, updating is recommend."),
UPDATE_HIGHLY_RECOMMENDED(UPDATE_AVAILABLE + ". We highly recommend updating because some important changes have been made."),
UPDATE_ANCIENT_VERSION(UPDATE_AVAILABLE + ". You are running an ancient version, updating is recommended."),
DOWNTIME_GENERIC("The {} is temporarily going down for maintenance soon."),
DOWNTIME_WITH_START("The {} is temporarily going down for maintenance on {}."),
DOWNTIME_TIMEFRAME(DOWNTIME_WITH_START + " The maintenance is expected to last till {}.");
private static final NewsItemMessage[] VALUES = values();
private final String messageFormat;
private final String[] messageSplitted;
NewsItemMessage(String messageFormat) {
this.messageFormat = messageFormat;
this.messageSplitted = messageFormat.split(" ");
}
public static NewsItemMessage getById(int id) {
return VALUES.length > id ? VALUES[id] : null;
}
public String getMessageFormat() {
return messageFormat;
}
public String getFormattedMessage(JsonArray serverArguments) {
int serverArgumentsIndex = 0;
StringBuilder message = new StringBuilder();
for (String split : messageSplitted) {
if (message.length() > 0) {
message.append(' ');
}
String result = split;
if (serverArgumentsIndex < serverArguments.size()) {
String argument = serverArguments.get(serverArgumentsIndex).getAsString();
result = result.replace("{}", argument);
if (!result.equals(split)) {
serverArgumentsIndex++;
}
}
message.append(result);
}
return message.toString();
}
@Override
public String toString() {
return getMessageFormat();
}
}

View File

@ -1,59 +0,0 @@
/*
* Copyright (c) 2019-2022 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/Geyser
*/
package org.geysermc.floodgate.news;
import com.google.gson.JsonObject;
import org.geysermc.floodgate.news.data.*;
import java.util.function.Function;
public enum NewsType {
BUILD_SPECIFIC(BuildSpecificData::read),
CHECK_AFTER(CheckAfterData::read),
ANNOUNCEMENT(AnnouncementData::read),
CONFIG_SPECIFIC(ConfigSpecificData::read);
private static final NewsType[] VALUES = values();
private final Function<JsonObject, ? extends ItemData> readFunction;
NewsType(Function<JsonObject, ? extends ItemData> readFunction) {
this.readFunction = readFunction;
}
public static NewsType getByName(String newsType) {
for (NewsType type : VALUES) {
if (type.name().equalsIgnoreCase(newsType)) {
return type;
}
}
return null;
}
public ItemData read(JsonObject data) {
return readFunction.apply(data);
}
}

View File

@ -1,63 +0,0 @@
/*
* Copyright (c) 2019-2022 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/Geyser
*/
package org.geysermc.floodgate.news.data;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.util.HashSet;
import java.util.Set;
public final class AnnouncementData implements ItemData {
private final Set<String> including = new HashSet<>();
private final Set<String> excluding = new HashSet<>();
private AnnouncementData() {}
public static AnnouncementData read(JsonObject data) {
AnnouncementData announcementData = new AnnouncementData();
if (data.has("including")) {
JsonArray including = data.getAsJsonArray("including");
for (JsonElement element : including) {
announcementData.including.add(element.getAsString());
}
}
if (data.has("excluding")) {
JsonArray including = data.getAsJsonArray("excluding");
for (JsonElement element : including) {
announcementData.excluding.add(element.getAsString());
}
}
return announcementData;
}
public boolean isAffected(String project) {
return !excluding.contains(project) && (including.isEmpty() || including.contains(project));
}
}

View File

@ -1,62 +0,0 @@
/*
* Copyright (c) 2019-2022 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/Geyser
*/
package org.geysermc.floodgate.news.data;
import com.google.gson.JsonObject;
public final class BuildSpecificData implements ItemData {
private String branch;
private boolean allAffected;
private int affectedGreaterThan;
private int affectedLessThan;
private BuildSpecificData() {}
public static BuildSpecificData read(JsonObject data) {
BuildSpecificData updateData = new BuildSpecificData();
updateData.branch = data.get("branch").getAsString();
JsonObject affectedBuilds = data.getAsJsonObject("affected_builds");
if (affectedBuilds.has("all")) {
updateData.allAffected = affectedBuilds.get("all").getAsBoolean();
}
if (!updateData.allAffected) {
updateData.affectedGreaterThan = affectedBuilds.get("gt").getAsInt();
updateData.affectedLessThan = affectedBuilds.get("lt").getAsInt();
}
return updateData;
}
public boolean isAffected(String branch, int buildId) {
return this.branch.equals(branch) &&
(allAffected || buildId > affectedGreaterThan && buildId < affectedLessThan);
}
public String getBranch() {
return branch;
}
}

View File

@ -1,44 +0,0 @@
/*
* Copyright (c) 2019-2022 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/Geyser
*/
package org.geysermc.floodgate.news.data;
import com.google.gson.JsonObject;
public final class CheckAfterData implements ItemData {
private long checkAfter;
private CheckAfterData() {}
public static CheckAfterData read(JsonObject data) {
CheckAfterData checkAfterData = new CheckAfterData();
checkAfterData.checkAfter = data.get("check_after").getAsLong();
return checkAfterData;
}
public long getCheckAfter() {
return checkAfter;
}
}

View File

@ -1,65 +0,0 @@
/*
* Copyright (c) 2019-2022 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/Geyser
*/
package org.geysermc.floodgate.news.data;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
public final class ConfigSpecificData implements ItemData {
private final Map<String, Pattern> affectedKeys = new HashMap<>();
private ConfigSpecificData() {}
public static ConfigSpecificData read(JsonObject data) {
ConfigSpecificData configSpecificData = new ConfigSpecificData();
JsonArray entries = data.getAsJsonArray("entries");
for (JsonElement element : entries) {
JsonObject entry = element.getAsJsonObject();
String key = entry.get("key").getAsString();
String pattern = entry.get("pattern").getAsString();
configSpecificData.affectedKeys.put(key, Pattern.compile(pattern));
}
return configSpecificData;
}
public boolean isAffected(Map<String, String> config) {
for (Map.Entry<String, Pattern> entry : affectedKeys.entrySet()) {
if (config.containsKey(entry.getKey())) {
String value = config.get(entry.getKey());
if (entry.getValue().matcher(value).matches()) {
return true;
}
}
}
return false;
}
}

View File

@ -1,29 +0,0 @@
/*
* Copyright (c) 2019-2022 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/Geyser
*/
package org.geysermc.floodgate.news.data;
public interface ItemData {
}

View File

@ -1,48 +0,0 @@
/*
* Copyright (c) 2019-2022 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/Geyser
*/
package org.geysermc.floodgate.pluginmessage;
import java.nio.charset.StandardCharsets;
public final class PluginMessageChannels {
public static final String SKIN = "floodgate:skin";
public static final String FORM = "floodgate:form";
public static final String TRANSFER = "floodgate:transfer";
public static final String PACKET = "floodgate:packet";
private static final byte[] FLOODGATE_REGISTER_DATA =
String.join("\0", SKIN, FORM, TRANSFER, PACKET)
.getBytes(StandardCharsets.UTF_8);
/**
* Get the prebuilt register data as a byte array
*
* @return the register data of the Floodgate channels
*/
public static byte[] getFloodgateRegisterData() {
return FLOODGATE_REGISTER_DATA;
}
}

View File

@ -1,112 +0,0 @@
/*
* Copyright (c) 2019-2022 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/Geyser
*/
package org.geysermc.floodgate.util;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* This class contains the raw data send by Geyser to Floodgate or from Floodgate to Floodgate. This
* class is only used internally, and you should look at FloodgatePlayer instead (FloodgatePlayer is
* present in the API module of the Floodgate repo)
*/
@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public final class BedrockData implements Cloneable {
public static final int EXPECTED_LENGTH = 12;
private final String version;
private final String username;
private final String xuid;
private final int deviceOs;
private final String languageCode;
private final int uiProfile;
private final int inputMode;
private final String ip;
private final LinkedPlayer linkedPlayer;
private final boolean fromProxy;
private final int subscribeId;
private final String verifyCode;
private final int dataLength;
public static BedrockData of(
String version, String username, String xuid, int deviceOs,
String languageCode, int uiProfile, int inputMode, String ip,
LinkedPlayer linkedPlayer, boolean fromProxy, int subscribeId,
String verifyCode) {
return new BedrockData(version, username, xuid, deviceOs, languageCode, inputMode,
uiProfile, ip, linkedPlayer, fromProxy, subscribeId, verifyCode, EXPECTED_LENGTH);
}
public static BedrockData of(
String version, String username, String xuid, int deviceOs,
String languageCode, int uiProfile, int inputMode, String ip,
int subscribeId, String verifyCode) {
return of(version, username, xuid, deviceOs, languageCode, uiProfile, inputMode, ip, null,
false, subscribeId, verifyCode);
}
public static BedrockData fromString(String data) {
String[] split = data.split("\0");
if (split.length != EXPECTED_LENGTH) {
return emptyData(split.length);
}
LinkedPlayer linkedPlayer = LinkedPlayer.fromString(split[8]);
// The format is the same as the order of the fields in this class
return new BedrockData(
split[0], split[1], split[2], Integer.parseInt(split[3]), split[4],
Integer.parseInt(split[5]), Integer.parseInt(split[6]), split[7], linkedPlayer,
"1".equals(split[9]), Integer.parseInt(split[10]), split[11], split.length
);
}
private static BedrockData emptyData(int dataLength) {
return new BedrockData(null, null, null, -1, null, -1, -1, null, null, false, -1, null,
dataLength);
}
public boolean hasPlayerLink() {
return linkedPlayer != null;
}
@Override
public String toString() {
// The format is the same as the order of the fields in this class
return version + '\0' + username + '\0' + xuid + '\0' + deviceOs + '\0' +
languageCode + '\0' + uiProfile + '\0' + inputMode + '\0' + ip + '\0' +
(linkedPlayer != null ? linkedPlayer.toString() : "null") + '\0' +
(fromProxy ? 1 : 0) + '\0' + subscribeId + '\0' + verifyCode;
}
@Override
public BedrockData clone() throws CloneNotSupportedException {
return (BedrockData) super.clone();
}
}

View File

@ -1,40 +0,0 @@
/*
* Copyright (c) 2019-2022 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/Geyser
*/
package org.geysermc.floodgate.util;
import lombok.Getter;
import lombok.Setter;
import java.util.Properties;
public final class FloodgateInfoHolder {
@Getter
@Setter
private static Object config;
@Getter
@Setter
private static Properties gitProperties;
}

View File

@ -1,32 +0,0 @@
/*
* Copyright (c) 2019-2022 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/Geyser
*/
package org.geysermc.floodgate.util;
public class InvalidFormatException extends Exception {
public InvalidFormatException(String message) {
super(message);
}
}

View File

@ -1,81 +0,0 @@
/*
* Copyright (c) 2019-2022 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/Geyser
*/
package org.geysermc.floodgate.util;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.UUID;
@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public final class LinkedPlayer implements Cloneable {
/**
* The Java username of the linked player
*/
private final String javaUsername;
/**
* The Java UUID of the linked player
*/
private final UUID javaUniqueId;
/**
* The UUID of the Bedrock player
*/
private final UUID bedrockId;
/**
* If the LinkedPlayer is sent from a different platform. For example the LinkedPlayer is from
* Bungee but the data has been sent to the Bukkit server.
*/
private boolean fromDifferentPlatform = false;
public static LinkedPlayer of(String javaUsername, UUID javaUniqueId, UUID bedrockId) {
return new LinkedPlayer(javaUsername, javaUniqueId, bedrockId);
}
public static LinkedPlayer fromString(String data) {
String[] split = data.split(";");
if (split.length != 3) {
return null;
}
LinkedPlayer player = new LinkedPlayer(
split[0], UUID.fromString(split[1]), UUID.fromString(split[2])
);
player.fromDifferentPlatform = true;
return player;
}
@Override
public String toString() {
return javaUsername + ';' + javaUniqueId.toString() + ';' + bedrockId.toString();
}
@Override
public LinkedPlayer clone() throws CloneNotSupportedException {
return (LinkedPlayer) super.clone();
}
}

View File

@ -1,91 +0,0 @@
/*
* Copyright (c) 2019-2022 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/Geyser
*/
package org.geysermc.floodgate.util;
public enum WebsocketEventType {
/**
* Sent once we successfully connected to the server
*/
SUBSCRIBER_CREATED(0),
/**
* Sent every time a subscriber got added or disconnected
*/
SUBSCRIBER_COUNT(1),
/**
* Sent once the creator disconnected. After this packet the server will automatically close the
* connection once the queue size (sent in {@link #ADDED_TO_QUEUE} and {@link #SKIN_UPLOADED}
* reaches 0.
*/
CREATOR_DISCONNECTED(4),
/**
* Sent every time a skin got added to the upload queue
*/
ADDED_TO_QUEUE(2),
/**
* Sent every time a skin got successfully uploaded
*/
SKIN_UPLOADED(3),
/**
* Sent every time a news item was added
*/
NEWS_ADDED(6),
/**
* Sent when the server wants you to know something. Currently used for violations that aren't
* bad enough to close the connection
*/
LOG_MESSAGE(5);
private static final WebsocketEventType[] VALUES;
static {
WebsocketEventType[] values = values();
VALUES = new WebsocketEventType[values.length];
for (WebsocketEventType value : values) {
VALUES[value.id] = value;
}
}
/**
* The ID is based of the time it got added. However, to keep the enum organized as time goes on,
* it looks nicer to sort the events based of categories.
*/
private final int id;
WebsocketEventType(int id) {
this.id = id;
}
public static WebsocketEventType fromId(int id) {
return VALUES.length > id ? VALUES[id] : null;
}
public int id() {
return id;
}
}

View File

@ -8,6 +8,7 @@ plugins {
dependencies {
api(libs.floodgate.core)
api(libs.floodgate.isolation)
annotationProcessor(libs.floodgate.core)
api(projects.api)

View File

@ -29,8 +29,6 @@ import org.geysermc.floodgate.core.skin.SkinApplier;
import org.geysermc.geyser.command.GeyserCommandManager;
import org.geysermc.geyser.configuration.GeyserConfiguration;
import org.geysermc.geyser.dump.BootstrapDumpInfo;
import org.geysermc.geyser.hybrid.FloodgateHybridProvider;
import org.geysermc.geyser.hybrid.HybridProvider;
import org.geysermc.geyser.level.GeyserWorldManager;
import org.geysermc.geyser.level.WorldManager;
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
@ -137,13 +135,6 @@ public interface GeyserBootstrap {
return Paths.get("logs/latest.log");
}
/**
* Creates the hybrid provider for this platform. The provider will differ based on server access.
*/
default HybridProvider createHybridProvider(GeyserImpl geyser) {
return new FloodgateHybridProvider(geyser);
}
/**
* Returns the skin applier for this platform, if the hybrid provider is integrated with the system.
*/

View File

@ -64,12 +64,13 @@ import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.erosion.UnixSocketClientListener;
import org.geysermc.geyser.event.GeyserEventBus;
import org.geysermc.geyser.extension.GeyserExtensionManager;
import org.geysermc.geyser.hybrid.HybridProvider;
import org.geysermc.geyser.floodgate.FloodgateProvider;
import org.geysermc.geyser.floodgate.NoFloodgateProvider;
import org.geysermc.geyser.floodgate.ProxyFloodgateProvider;
import org.geysermc.geyser.level.WorldManager;
import org.geysermc.geyser.network.netty.GeyserServer;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.registry.loader.RegistryLoaders;
import org.geysermc.geyser.scoreboard.ScoreboardUpdater;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.PendingMicrosoftAuthentication;
@ -131,7 +132,7 @@ public class GeyserImpl implements GeyserApi {
@Setter
private static boolean shouldStartListener = true;
private HybridProvider hybridProvider;
private final FloodgateProvider floodgateProvider;
private BedrockSkinUploader skinUploader;
private NewsHandler newsHandler;
@ -156,16 +157,18 @@ public class GeyserImpl implements GeyserApi {
private static GeyserImpl instance;
private final FloodgatePlatform floodgatePlatform;
private GeyserImpl(PlatformType platformType, GeyserBootstrap bootstrap, FloodgatePlatform floodgatePlatform) {
instance = this;
this.floodgatePlatform = floodgatePlatform;
if (floodgatePlatform != null) {
floodgatePlatform.load();
floodgatePlatform.enable();
// this.floodgatePlatform = floodgatePlatform.isProxy() ? new ProxyFloodgateProvider(floodgatePlatform) : new IntegratedFloodgateProvider(floodgatePlatform);
// this.floodgateProvider = new IntegratedFloodgateProvider(floodgatePlatform);
this.floodgateProvider = new ProxyFloodgateProvider(floodgatePlatform);
} else {
this.floodgateProvider = new NoFloodgateProvider();
Geyser.set(this);
}
@ -314,7 +317,7 @@ public class GeyserImpl implements GeyserApi {
}
}
boolean floodgatePresent = bootstrap.testFloodgatePluginPresent();
boolean floodgatePresent = bootstrap.testFloodgatePluginPresent() || floodgateProvider != null; //todo
if (config.getRemote().authType() == AuthType.FLOODGATE && !floodgatePresent) {
logger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " "
+ GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling"));
@ -383,7 +386,6 @@ public class GeyserImpl implements GeyserApi {
}
if (config.getRemote().authType() == AuthType.FLOODGATE) {
hybridProvider = bootstrap.createHybridProvider(this);
try {
// Note: this is positioned after the bind so the skin uploader doesn't try to run if Geyser fails
// to load successfully. Spigot complains about class loader if the plugin is disabled.

View File

@ -33,7 +33,6 @@ import org.geysermc.geyser.command.GeyserCommandSource;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.util.LoopbackUtil;
import org.geysermc.geyser.util.PlatformType;
import org.geysermc.geyser.util.WebUtils;
import org.jetbrains.annotations.Nullable;

View File

@ -252,6 +252,6 @@ public class SessionPlayerEntity extends PlayerEntity {
@Override
public UUID getTabListUuid() {
return session.getAuthData().uuid();
return session.identity();
}
}

View File

@ -34,7 +34,6 @@ import org.geysermc.event.subscribe.Subscribe;
import org.geysermc.geyser.api.event.EventBus;
import org.geysermc.geyser.api.event.EventRegistrar;
import org.geysermc.geyser.api.event.EventSubscriber;
import org.geysermc.geyser.api.extension.Extension;
import java.util.Set;
import java.util.function.BiConsumer;
@ -67,6 +66,6 @@ public final class GeyserEventBus extends OwnedEventBusImpl<EventRegistrar, Even
@Override
@NonNull
public <T extends Event> Set<? extends EventSubscriber<EventRegistrar, T>> subscribers(@NonNull Class<T> eventClass) {
return castGenericSet(super.subscribers(eventClass));
return castGenericNullableSet(super.subscribers(eventClass));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
* 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
@ -23,18 +23,18 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.floodgate.crypto;
package org.geysermc.geyser.floodgate;
import java.util.Base64;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.session.GeyserSession;
public final class Base64Topping implements Topping {
@Override
public byte[] encode(byte[] data) {
return Base64.getEncoder().encode(data);
}
public interface FloodgateProvider {
void onSkinUpload(GeyserSession session, String value, String signature);
@Override
public byte[] decode(byte[] data) {
return Base64.getDecoder().decode(data);
}
/**
* Called before Geyser sends the ClientIntention to the Java server.
*
* @return data to add to the hostname
*/
@Nullable String onClientIntention(GeyserSession session) throws Exception;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* 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
@ -23,23 +23,25 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.hybrid;
package org.geysermc.geyser.floodgate;
import io.netty.util.AttributeKey;
import org.geysermc.floodgate.core.crypto.FloodgateCipher;
import org.geysermc.floodgate.core.FloodgatePlatform;
import org.geysermc.floodgate.core.connection.ConnectionManager;
import org.geysermc.floodgate.core.skin.SkinApplier;
import org.geysermc.floodgate.core.skin.SkinDataImpl;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.session.GeyserSession;
public class IntegratedHybridProvider implements HybridProvider {
public class IntegratedFloodgateProvider implements FloodgateProvider {
// TODO This will probably end up as its own class.
public static final AttributeKey<GeyserSession> SESSION_KEY = AttributeKey.valueOf("geyser-session");
private final SkinApplier skinApplier;
private final ConnectionManager connectionManager;
public IntegratedHybridProvider(GeyserImpl geyser) {
skinApplier = geyser.getBootstrap().createSkinApplier();
public IntegratedFloodgateProvider(FloodgatePlatform platform) {
skinApplier = platform.getBean(SkinApplier.class);
connectionManager = platform.getBean(ConnectionManager.class);
}
@Override
@ -48,7 +50,8 @@ public class IntegratedHybridProvider implements HybridProvider {
}
@Override
public FloodgateCipher getCipher() {
throw new UnsupportedOperationException();
public String onClientIntention(GeyserSession session) {
connectionManager.addConnection(session);
return null;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
* 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
@ -23,13 +23,18 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.hybrid;
package org.geysermc.geyser.floodgate;
import org.geysermc.floodgate.core.crypto.FloodgateCipher;
import org.geysermc.geyser.session.GeyserSession;
public interface HybridProvider {
void onSkinUpload(GeyserSession session, String value, String signature);
public final class NoFloodgateProvider implements FloodgateProvider {
@Override
public void onSkinUpload(GeyserSession session, String value, String signature) {
FloodgateCipher getCipher();
}
@Override
public String onClientIntention(GeyserSession session) {
return null;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
* 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
@ -23,19 +23,19 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.hybrid;
import org.geysermc.floodgate.core.crypto.FloodgateCipher;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.session.GeyserSession;
package org.geysermc.geyser.floodgate;
import java.nio.charset.StandardCharsets;
import org.geysermc.floodgate.core.FloodgatePlatform;
import org.geysermc.floodgate.core.crypto.FloodgateDataCodec;
import org.geysermc.geyser.session.GeyserSession;
public final class FloodgateHybridProvider implements HybridProvider {
private final FloodgateCipher cipher;
//todo Floodgate should be responsible for forwarding its messages
public final class ProxyFloodgateProvider implements FloodgateProvider {
private final FloodgateDataCodec dataCodec;
public FloodgateHybridProvider(GeyserImpl geyser) {
cipher = geyser.getFloodgatePlatform().getBean(FloodgateCipher.class);
public ProxyFloodgateProvider(FloodgatePlatform platform) {
dataCodec = platform.getBean(FloodgateDataCodec.class);
}
@Override
@ -47,7 +47,7 @@ public final class FloodgateHybridProvider implements HybridProvider {
}
@Override
public FloodgateCipher getCipher() {
return cipher;
public String onClientIntention(GeyserSession session) throws Exception {
return dataCodec.encodeToString(session);
}
}

View File

@ -1,43 +0,0 @@
/*
* Copyright (c) 2019-2022 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/Geyser
*/
package org.geysermc.geyser.hybrid;
import org.geysermc.floodgate.core.crypto.FloodgateCipher;
import org.geysermc.geyser.GeyserImpl;
public final class ProxyHybridProvider extends IntegratedHybridProvider {
private final FloodgateCipher cipher;
public ProxyHybridProvider(GeyserImpl geyser) {
super(geyser);
this.cipher = geyser.getFloodgatePlatform().getBean(FloodgateCipher.class);
}
@Override
public FloodgateCipher getCipher() {
return cipher;
}
}

View File

@ -29,7 +29,7 @@ import io.netty.channel.local.LocalChannel;
import io.netty.channel.local.LocalServerChannel;
import io.netty.util.Attribute;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.hybrid.IntegratedHybridProvider;
import org.geysermc.geyser.floodgate.IntegratedFloodgateProvider;
import org.geysermc.geyser.session.GeyserSession;
/**
@ -44,12 +44,12 @@ public class LocalServerChannelWrapper extends LocalServerChannel {
LocalChannelWrapper channel = new LocalChannelWrapper(this, peer);
channel.wrapper().remoteAddress(((LocalChannelWithRemoteAddress) peer).spoofedRemoteAddress());
if (GeyserImpl.getInstance().getHybridProvider() instanceof IntegratedHybridProvider) {
Attribute<GeyserSession> attribute = peer.attr(IntegratedHybridProvider.SESSION_KEY);
if (GeyserImpl.getInstance().getFloodgateProvider() instanceof IntegratedFloodgateProvider) {
Attribute<GeyserSession> attribute = peer.attr(IntegratedFloodgateProvider.SESSION_KEY);
GeyserSession session = attribute.get();
// Garbage collect since it's no longer relevant for the PacketLib side.
attribute.set(null);
channel.attr(IntegratedHybridProvider.SESSION_KEY).set(session);
channel.attr(IntegratedFloodgateProvider.SESSION_KEY).set(session);
}
return channel;
}

View File

@ -39,7 +39,7 @@ import io.netty.channel.unix.PreferredDirectByteBufAllocator;
import io.netty.handler.codec.haproxy.*;
import io.netty.util.Attribute;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.hybrid.IntegratedHybridProvider;
import org.geysermc.geyser.floodgate.IntegratedFloodgateProvider;
import org.geysermc.geyser.session.GeyserSession;
import javax.annotation.Nullable;
@ -98,8 +98,8 @@ public final class LocalSession extends TcpSession {
addHAProxySupport(pipeline);
if (GeyserImpl.getInstance().getHybridProvider() instanceof IntegratedHybridProvider) {
Attribute<GeyserSession> attribute = channel.attr(IntegratedHybridProvider.SESSION_KEY);
if (GeyserImpl.getInstance().getFloodgateProvider() instanceof IntegratedFloodgateProvider) {
Attribute<GeyserSession> attribute = channel.attr(IntegratedFloodgateProvider.SESSION_KEY);
attribute.set(session);
}
}

View File

@ -35,7 +35,6 @@ import org.geysermc.geyser.registry.loader.RegistryLoaders;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.util.PlatformType;
import java.util.Collections;
import java.util.IdentityHashMap;

View File

@ -74,6 +74,25 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import java.net.ConnectException;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
@ -83,16 +102,55 @@ 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.cloudburstmc.math.vector.*;
import org.cloudburstmc.math.vector.Vector2f;
import org.cloudburstmc.math.vector.Vector2i;
import org.cloudburstmc.math.vector.Vector3d;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.protocol.bedrock.BedrockDisconnectReasons;
import org.cloudburstmc.protocol.bedrock.BedrockServerSession;
import org.cloudburstmc.protocol.bedrock.data.*;
import org.cloudburstmc.protocol.bedrock.data.Ability;
import org.cloudburstmc.protocol.bedrock.data.AbilityLayer;
import org.cloudburstmc.protocol.bedrock.data.AttributeData;
import org.cloudburstmc.protocol.bedrock.data.AuthoritativeMovementMode;
import org.cloudburstmc.protocol.bedrock.data.CameraShakeAction;
import org.cloudburstmc.protocol.bedrock.data.CameraShakeType;
import org.cloudburstmc.protocol.bedrock.data.ChatRestrictionLevel;
import org.cloudburstmc.protocol.bedrock.data.ExperimentData;
import org.cloudburstmc.protocol.bedrock.data.GamePublishSetting;
import org.cloudburstmc.protocol.bedrock.data.GameRuleData;
import org.cloudburstmc.protocol.bedrock.data.GameType;
import org.cloudburstmc.protocol.bedrock.data.PlayerPermission;
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
import org.cloudburstmc.protocol.bedrock.data.SpawnBiomeType;
import org.cloudburstmc.protocol.bedrock.data.command.CommandEnumData;
import org.cloudburstmc.protocol.bedrock.data.command.CommandPermission;
import org.cloudburstmc.protocol.bedrock.data.command.SoftEnumUpdateType;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.*;
import org.cloudburstmc.protocol.bedrock.packet.AvailableEntityIdentifiersPacket;
import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket;
import org.cloudburstmc.protocol.bedrock.packet.BiomeDefinitionListPacket;
import org.cloudburstmc.protocol.bedrock.packet.CameraShakePacket;
import org.cloudburstmc.protocol.bedrock.packet.ChunkRadiusUpdatedPacket;
import org.cloudburstmc.protocol.bedrock.packet.ClientboundMapItemDataPacket;
import org.cloudburstmc.protocol.bedrock.packet.CraftingDataPacket;
import org.cloudburstmc.protocol.bedrock.packet.CreativeContentPacket;
import org.cloudburstmc.protocol.bedrock.packet.EmoteListPacket;
import org.cloudburstmc.protocol.bedrock.packet.EmotePacket;
import org.cloudburstmc.protocol.bedrock.packet.GameRulesChangedPacket;
import org.cloudburstmc.protocol.bedrock.packet.ItemComponentPacket;
import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet;
import org.cloudburstmc.protocol.bedrock.packet.PlayStatusPacket;
import org.cloudburstmc.protocol.bedrock.packet.PlayerFogPacket;
import org.cloudburstmc.protocol.bedrock.packet.SetTimePacket;
import org.cloudburstmc.protocol.bedrock.packet.StartGamePacket;
import org.cloudburstmc.protocol.bedrock.packet.TextPacket;
import org.cloudburstmc.protocol.bedrock.packet.TransferPacket;
import org.cloudburstmc.protocol.bedrock.packet.UpdateAbilitiesPacket;
import org.cloudburstmc.protocol.bedrock.packet.UpdateAdventureSettingsPacket;
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
import org.cloudburstmc.protocol.bedrock.packet.UpdateSoftEnumPacket;
import org.cloudburstmc.protocol.common.DefinitionRegistry;
import org.cloudburstmc.protocol.common.util.OptionalBoolean;
import org.geysermc.api.util.BedrockPlatform;
@ -100,8 +158,8 @@ 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.crypto.FloodgateCipher;
import org.geysermc.floodgate.util.BedrockData;
import org.geysermc.floodgate.core.connection.FloodgateConnection;
import org.geysermc.floodgate.util.LinkedPlayer;
import org.geysermc.geyser.Constants;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.api.bedrock.camera.CameraShake;
@ -123,8 +181,7 @@ import org.geysermc.geyser.entity.type.Tickable;
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
import org.geysermc.geyser.erosion.AbstractGeyserboundPacketHandler;
import org.geysermc.geyser.erosion.GeyserboundHandshakePacketHandler;
import org.geysermc.geyser.hybrid.FloodgateHybridProvider;
import org.geysermc.geyser.hybrid.HybridProvider;
import org.geysermc.geyser.floodgate.FloodgateProvider;
import org.geysermc.geyser.inventory.Inventory;
import org.geysermc.geyser.inventory.PlayerInventory;
import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
@ -139,8 +196,20 @@ import org.geysermc.geyser.registry.type.BlockMappings;
import org.geysermc.geyser.registry.type.ItemMappings;
import org.geysermc.geyser.session.auth.AuthData;
import org.geysermc.geyser.session.auth.BedrockClientData;
import org.geysermc.geyser.session.cache.*;
import org.geysermc.geyser.skin.BedrockSkinUploader;
import org.geysermc.geyser.session.cache.AdvancementsCache;
import org.geysermc.geyser.session.cache.BookEditCache;
import org.geysermc.geyser.session.cache.ChunkCache;
import org.geysermc.geyser.session.cache.EntityCache;
import org.geysermc.geyser.session.cache.EntityEffectCache;
import org.geysermc.geyser.session.cache.FormCache;
import org.geysermc.geyser.session.cache.LodestoneCache;
import org.geysermc.geyser.session.cache.PistonCache;
import org.geysermc.geyser.session.cache.PreferencesCache;
import org.geysermc.geyser.session.cache.SkullCache;
import org.geysermc.geyser.session.cache.TagCache;
import org.geysermc.geyser.session.cache.TeleportCache;
import org.geysermc.geyser.session.cache.WorldBorder;
import org.geysermc.geyser.session.cache.WorldCache;
import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.text.MinecraftLocale;
import org.geysermc.geyser.text.TextDecoration;
@ -152,19 +221,8 @@ import org.geysermc.geyser.util.EntityUtils;
import org.geysermc.geyser.util.LoginEncryptionUtils;
import org.jetbrains.annotations.NotNull;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@Getter
public class GeyserSession implements GeyserConnection, GeyserCommandSource {
public class GeyserSession extends FloodgateConnection implements GeyserConnection, GeyserCommandSource {
private final GeyserImpl geyser;
private final UpstreamSession upstream;
@ -343,7 +401,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
/**
* Tracks the original speed attribute.
*
* <p>
* We need to do this in order to emulate speeds when sneaking under 1.5-blocks-tall areas if the player isn't sneaking,
* and when crawling.
*/
@ -961,43 +1019,21 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
public void packetSending(PacketSendingEvent event) {
//todo move this somewhere else
if (event.getPacket() instanceof ClientIntentionPacket) {
String addressSuffix;
HybridProvider provider;
if (floodgate && (provider = geyser.getHybridProvider()) instanceof FloodgateHybridProvider) {
byte[] encryptedData;
String addedData;
try {
BedrockSkinUploader skinUploader = geyser.getSkinUploader();
FloodgateCipher cipher = provider.getCipher();
FloodgateProvider provider = geyser.getFloodgateProvider();
try {
addedData = provider.onClientIntention(GeyserSession.this);
} catch (Exception exception) {
geyser.getLogger().error(GeyserLocale.getLocaleStringLog("geyser.auth.floodgate.encrypt_fail"), exception);
disconnect(GeyserLocale.getPlayerLocaleString("geyser.auth.floodgate.encryption_fail", getClientData().getLanguageCode()));
return;
}
String bedrockAddress = upstream.getAddress().getAddress().getHostAddress();
// both BungeeCord and Velocity remove the IPv6 scope (if there is one) for Spigot
int ipv6ScopeIndex = bedrockAddress.indexOf('%');
if (ipv6ScopeIndex != -1) {
bedrockAddress = bedrockAddress.substring(0, ipv6ScopeIndex);
}
encryptedData = cipher.encryptFromString(BedrockData.of(
clientData.getGameVersion(),
authData.name(),
authData.xuid(),
clientData.getDeviceOs().ordinal(),
clientData.getLanguageCode(),
clientData.getUiProfile().ordinal(),
clientData.getCurrentInputMode().ordinal(),
bedrockAddress,
skinUploader.getId(),
skinUploader.getVerifyCode()
).toString());
} catch (Exception e) {
geyser.getLogger().error(GeyserLocale.getLocaleStringLog("geyser.auth.floodgate.encrypt_fail"), e);
disconnect(GeyserLocale.getPlayerLocaleString("geyser.auth.floodgate.encryption_fail", getClientData().getLanguageCode()));
return;
}
addressSuffix = '\0' + new String(encryptedData, StandardCharsets.UTF_8);
if (addedData != null) {
addedData = '\0' + addedData;
} else {
addressSuffix = "";
addedData = "";
}
ClientIntentionPacket intentionPacket = event.getPacket();
@ -1009,7 +1045,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
address = intentionPacket.getHostname();
}
event.setPacket(intentionPacket.withHostname(address + addressSuffix));
event.setPacket(intentionPacket.withHostname(address + addedData));
}
}
@ -1480,11 +1516,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
upstream.sendPacket(chunkRadiusUpdatedPacket);
}
@Override
public InetSocketAddress socketAddress() {
return this.upstream.getAddress();
}
@Override
public boolean sendForm(@NonNull Form form) {
formCache.showForm(form);
@ -1497,22 +1528,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
return true;
}
/**
* @deprecated since Cumulus version 1.1, and will be removed when Cumulus 2.0 releases. Please use the new forms instead.
*/
@Deprecated
public void sendForm(org.geysermc.cumulus.Form<?> form) {
sendForm(form.newForm());
}
/**
* @deprecated since Cumulus version 1.1, and will be removed when Cumulus 2.0 releases. Please use the new forms instead.
*/
@Deprecated
public void sendForm(org.geysermc.cumulus.util.FormBuilder<?, ?> formBuilder) {
sendForm(formBuilder.build());
}
private void startGame() {
this.upstream.getCodecHelper().setItemDefinitions(this.itemMappings);
this.upstream.getCodecHelper().setBlockDefinitions((DefinitionRegistry) this.blockMappings); //FIXME
@ -1947,8 +1962,18 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
}
@Override
public boolean isLinked() {
return false; //todo
public @NonNull UUID identity() {
return authData.uuid();
}
@Override
public @NonNull InetAddress ip() {
return upstream.getAddress().getAddress();
}
@Override
public @MonotonicNonNull LinkedPlayer linkedPlayer() {
return null; //todo
}
@SuppressWarnings("ConstantConditions") // Need to enforce the parameter annotations

View File

@ -140,7 +140,7 @@ public class AdvancementsCache {
session.sendDownstreamPacket(new ServerboundSeenAdvancementsPacket());
}).validResultHandler((response) -> {
if (response.getClickedButtonId() < visibleAdvancements.size()) {
if (response.clickedButtonId() < visibleAdvancements.size()) {
GeyserAdvancement advancement = visibleAdvancements.get(response.clickedButtonId());
buildAndShowInfoForm(advancement);
} else {

View File

@ -118,7 +118,7 @@ public final class BedrockSkinUploader {
String value = data.get("value").asText();
String signature = data.get("signature").asText();
geyser.getHybridProvider().onSkinUpload(session, value, signature);
geyser.getFloodgateProvider().onSkinUpload(session, value, signature);
}
break;
case LOG_MESSAGE:

View File

@ -4,7 +4,7 @@ floodgate = "development-2.2.2-SNAPSHOT"
cumulus = "1.1.2"
erosion = "1.0-20230406.174837-8"
events = "1.1-SNAPSHOT"
jackson = { strictly = "2.14.0" } # Don't let other dependencies override
jackson = "2.14.2"
fastutil = "8.5.2"
netty = "4.1.80.Final"
guava = "29.0-jre"
@ -27,7 +27,7 @@ folia = "1.19.4-R0.1-SNAPSHOT"
viaversion = "4.0.0"
adapters = "1.9-SNAPSHOT"
commodore = "2.2"
bungeecord = "a7c6ede"
bungeecord = "master-SNAPSHOT"
velocity = "3.1.1"
fabric-minecraft = "1.20"
fabric-loader = "0.14.21"
@ -39,6 +39,7 @@ cumulus = { group = "org.geysermc.cumulus", name = "cumulus", version.ref = "cum
events = { group = "org.geysermc.event", name = "events", version.ref = "events" }
floodgate-core = { module = "org.geysermc.floodgate:core", version.ref = "floodgate" }
floodgate-isolation = { module = "org.geysermc.floodgate:isolation", version.ref = "floodgate" }
floodgate-bungee = { module = "org.geysermc.floodgate:bungee-base", version.ref = "floodgate" }
floodgate-spigot = { module = "org.geysermc.floodgate:spigot-base", version.ref = "floodgate" }
floodgate-velocity = { module = "org.geysermc.floodgate:velocity-base", version.ref = "floodgate" }

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@ -64,7 +64,6 @@ include(":fabric")
include(":spigot")
include(":standalone")
include(":velocity")
include(":common")
include(":core")
// Specify project dirs