Removed support for unofficial clients

This commit is contained in:
RaphiMC 2023-05-09 23:51:31 +02:00
parent ea07e2876a
commit cd8055a140
8 changed files with 1 additions and 539 deletions

View File

@ -18,7 +18,6 @@ For a full user guide go to the [Usage for Players](#usage-for-players-gui) sect
- Release (1.7.2 - 1.19.4)
- Bedrock Edition (Needs the [Geyser plugin](https://github.com/RaphiMC/ViaProxyGeyserPlugin))
- Classic, Alpha, Beta, Release 1.0 - 1.6.4 (Only passthrough)
- Eaglercraft (1.5.2 / 1.8)
ViaProxy supports joining to any of the listed server version from any of the listed client versions.
@ -69,6 +68,7 @@ ViaProxy has a plugin API which allows you to create plugins for ViaProxy.
Documentation and examples:
- [NoLocalConnections](https://github.com/Lenni0451/NoLocalConnections)
- [ViaProxyMultiLaunch](https://github.com/Lenni0451/ViaProxyMultiLaunch)
- [ViaProxyGeyserPlugin](https://github.com/RaphiMC/ViaProxyGeyserPlugin)
## Contact
If you encounter any issues, please report them on the

View File

@ -59,7 +59,6 @@ public class Options {
public static String RESOURCE_PACK_URL; // Example: http://example.com/resourcepack.zip
public static boolean SERVER_HAPROXY_PROTOCOL;
public static boolean LEGACY_CLIENT_PASSTHROUGH;
public static boolean ALLOW_EAGLERCRAFT_CLIENTS;
public static void parse(final String[] args) throws IOException {
final OptionParser parser = new OptionParser();
@ -81,7 +80,6 @@ public class Options {
final OptionSpec<String> proxyUrl = parser.acceptsAll(asList("proxy_url", "proxy"), "URL of a SOCKS(4/5)/HTTP(S) proxy which will be used for backend TCP connections").withRequiredArg().ofType(String.class);
final OptionSpec<Void> serverHaProxyProtocol = parser.acceptsAll(asList("server-haproxy-protocol", "server-haproxy"), "Send HAProxy protocol messages to the backend server");
final OptionSpec<Void> legacyClientPassthrough = parser.acceptsAll(asList("legacy_client_passthrough", "legacy_passthrough"), "Allow <= 1.6.4 clients to connect to the backend server (No protocol translation)");
final OptionSpec<Void> allowEaglerCraftClients = parser.acceptsAll(asList("allow_eaglercraft_clients", "allow_eaglercraft"), "Allow Eaglercraft clients to connect to ViaProxy");
PluginManager.EVENT_MANAGER.call(new PreOptionsParseEvent(parser));
final OptionSet options = parser.parse(args);
@ -121,7 +119,6 @@ public class Options {
}
SERVER_HAPROXY_PROTOCOL = options.has(serverHaProxyProtocol);
LEGACY_CLIENT_PASSTHROUGH = options.has(legacyClientPassthrough);
ALLOW_EAGLERCRAFT_CLIENTS = options.has(allowEaglerCraftClients);
PluginManager.EVENT_MANAGER.call(new PostOptionsParseEvent(options));
}

View File

@ -26,22 +26,12 @@ import net.raphimc.viaproxy.cli.options.Options;
import net.raphimc.viaproxy.plugins.PluginManager;
import net.raphimc.viaproxy.plugins.events.Client2ProxyChannelInitializeEvent;
import net.raphimc.viaproxy.plugins.events.types.ITyped;
import net.raphimc.viaproxy.proxy.client2proxy.eaglercraft.EaglercraftInitialHandler;
import net.raphimc.viaproxy.proxy.client2proxy.passthrough.LegacyClientPassthroughHandler;
import java.util.function.Supplier;
public class Client2ProxyChannelInitializer extends MinecraftChannelInitializer {
public static final String EAGLERCRAFT_INITIAL_HANDLER_NAME = "eaglercraft-initial-handler";
public static final String WEBSOCKET_SSL_HANDLER_NAME = "ws-ssl-handler";
public static final String WEBSOCKET_HTTP_CODEC_NAME = "ws-http-codec";
public static final String WEBSOCKET_HTTP_AGGREGATOR_NAME = "ws-http-aggregator";
public static final String WEBSOCKET_COMPRESSION_NAME = "ws-compression";
public static final String WEBSOCKET_HANDLER_NAME = "ws-handler";
public static final String WEBSOCKET_ACTIVE_NOTIFIER_NAME = "ws-active-notifier";
public static final String EAGLERCRAFT_HANDLER_NAME = "eaglercraft-handler";
public static final String LEGACY_PASSTHROUGH_HANDLER_NAME = "legacy-passthrough-handler";
public Client2ProxyChannelInitializer(final Supplier<ChannelHandler> handlerSupplier) {
@ -55,9 +45,6 @@ public class Client2ProxyChannelInitializer extends MinecraftChannelInitializer
return;
}
if (Options.ALLOW_EAGLERCRAFT_CLIENTS) {
channel.pipeline().addLast(EAGLERCRAFT_INITIAL_HANDLER_NAME, new EaglercraftInitialHandler());
}
if (Options.LEGACY_CLIENT_PASSTHROUGH) {
channel.pipeline().addLast(LEGACY_PASSTHROUGH_HANDLER_NAME, new LegacyClientPassthroughHandler());
}

View File

@ -1,389 +0,0 @@
/*
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.raphimc.viaproxy.proxy.client2proxy.eaglercraft;
import com.google.common.net.HostAndPort;
import com.viaversion.viaversion.libs.gson.JsonArray;
import com.viaversion.viaversion.libs.gson.JsonObject;
import com.viaversion.viaversion.libs.gson.JsonParser;
import com.viaversion.viaversion.protocols.base.ClientboundStatusPackets;
import com.viaversion.viaversion.protocols.base.ServerboundHandshakePackets;
import com.viaversion.viaversion.protocols.base.ServerboundLoginPackets;
import com.viaversion.viaversion.protocols.base.ServerboundStatusPackets;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import net.lenni0451.mcstructs.text.serializer.TextComponentSerializer;
import net.raphimc.netminecraft.constants.ConnectionState;
import net.raphimc.netminecraft.constants.MCPackets;
import net.raphimc.netminecraft.constants.MCPipeline;
import net.raphimc.netminecraft.packet.PacketTypes;
import net.raphimc.vialegacy.protocols.release.protocol1_6_1to1_5_2.ServerboundPackets1_5_2;
import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.types.Types1_6_4;
import net.raphimc.viaprotocolhack.util.VersionEnum;
import net.raphimc.viaproxy.ViaProxy;
import net.raphimc.viaproxy.proxy.client2proxy.Client2ProxyChannelInitializer;
import net.raphimc.viaproxy.util.logging.Logger;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.UUID;
// Thanks to ayunami2000 for helping with the eaglercraft protocol
public class EaglercraftHandler extends MessageToMessageCodec<WebSocketFrame, ByteBuf> {
private static final int CLIENT_VERSION = 0x01;
private static final int SERVER_VERSION = 0x02;
private static final int VERSION_MISMATCH = 0x03;
private static final int CLIENT_REQUEST_LOGIN = 0x04;
private static final int SERVER_ALLOW_LOGIN = 0x05;
private static final int SERVER_DENY_LOGIN = 0x06;
private static final int CLIENT_PROFILE_DATA = 0x07;
private static final int CLIENT_FINISH_LOGIN = 0x08;
private static final int SERVER_FINISH_LOGIN = 0x09;
private static final int SERVER_ERROR = 0xFF;
private HostAndPort host;
private State state = State.PRE_HANDSHAKE;
private VersionEnum version;
private int pluginMessageId;
private String username;
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.channel().attr(MCPipeline.COMPRESSION_THRESHOLD_ATTRIBUTE_KEY).set(-2); // Disable automatic compression in Proxy2ServerHandler
ctx.pipeline().remove(MCPipeline.SIZER_HANDLER_NAME);
super.channelActive(ctx);
}
@Override
protected void encode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws IOException {
if (this.state == State.STATUS) {
final int packetId = PacketTypes.readVarInt(in);
if (packetId != ClientboundStatusPackets.STATUS_RESPONSE.getId()) {
throw new IllegalStateException("Unexpected packet id " + packetId);
}
final JsonObject root = JsonParser.parseString(PacketTypes.readString(in, Short.MAX_VALUE)).getAsJsonObject();
final JsonObject response = new JsonObject();
response.addProperty("name", "ViaProxy");
response.addProperty("brand", "ViaProxy");
if (root.has("version")) {
response.add("vers", root.getAsJsonObject("version").get("name"));
} else {
response.addProperty("vers", "Unknown");
}
response.addProperty("cracked", true);
response.addProperty("secure", false);
response.addProperty("time", System.currentTimeMillis());
response.addProperty("uuid", UUID.randomUUID().toString());
response.addProperty("type", "motd");
final JsonObject data = new JsonObject();
data.addProperty("cache", false);
final JsonArray motd = new JsonArray();
if (root.has("description")) {
final String[] motdLines = TextComponentSerializer.V1_8.deserialize(root.get("description").toString()).asLegacyFormatString().split("\n");
for (String motdLine : motdLines) {
motd.add(motdLine);
}
}
data.add("motd", motd);
data.addProperty("icon", root.has("favicon"));
if (root.has("players")) {
final JsonObject javaPlayers = root.getAsJsonObject("players");
data.add("online", javaPlayers.get("online"));
data.add("max", javaPlayers.get("max"));
final JsonArray players = new JsonArray();
if (javaPlayers.has("sample")) {
javaPlayers.getAsJsonArray("sample").forEach(player -> players.add(TextComponentSerializer.V1_8.deserialize(player.getAsJsonObject().get("name").getAsString()).asLegacyFormatString()));
}
data.add("players", players);
}
response.add("data", data);
out.add(new TextWebSocketFrame(response.toString()));
if (root.has("favicon")) {
final BufferedImage icon = ImageIO.read(new ByteArrayInputStream(Base64.getDecoder().decode(root.get("favicon").getAsString().substring(22).replace("\n", "").getBytes(StandardCharsets.UTF_8))));
final int[] pixels = icon.getRGB(0, 0, 64, 64, null, 0, 64);
final byte[] iconPixels = new byte[64 * 64 * 4];
for (int i = 0; i < 64 * 64; ++i) {
iconPixels[i * 4] = (byte) ((pixels[i] >> 16) & 0xFF);
iconPixels[i * 4 + 1] = (byte) ((pixels[i] >> 8) & 0xFF);
iconPixels[i * 4 + 2] = (byte) (pixels[i] & 0xFF);
iconPixels[i * 4 + 3] = (byte) ((pixels[i] >> 24) & 0xFF);
}
out.add(new BinaryWebSocketFrame(ctx.alloc().buffer().writeBytes(iconPixels)));
}
} else if (this.state == State.LOGIN_COMPLETE) {
out.add(new BinaryWebSocketFrame(in.retain()));
} else {
throw new IllegalStateException("Cannot send packets before login is completed");
}
}
@Override
protected void decode(ChannelHandlerContext ctx, WebSocketFrame in, List<Object> out) throws Exception {
if (in instanceof BinaryWebSocketFrame) {
final ByteBuf data = in.content();
switch (this.state) {
case PRE_HANDSHAKE:
if (data.readableBytes() >= 2) { // Check for legacy client
if (data.getByte(0) == (byte) 2 && data.getByte(1) == (byte) 69) {
data.setByte(1, 61); // 1.5.2 protocol id
this.state = State.LOGIN_COMPLETE;
this.version = VersionEnum.r1_5_2;
out.add(data.retain());
break;
}
}
this.state = State.HANDSHAKE;
case HANDSHAKE:
int packetId = data.readUnsignedByte(); // packet id
if (packetId == CLIENT_VERSION) {
int eaglercraftVersion = data.readUnsignedByte(); // eaglercraft version
final int minecraftVersion;
if (eaglercraftVersion == 1) {
minecraftVersion = data.readUnsignedByte(); // minecraft version
} else if (eaglercraftVersion == 2) {
int count = data.readUnsignedShort(); // eaglercraft versions
final List<Integer> eaglercraftVersions = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
eaglercraftVersions.add(data.readUnsignedShort()); // eaglercraft version id
}
if (!eaglercraftVersions.contains(2) && !eaglercraftVersions.contains(3)) {
Logger.LOGGER.error("No supported eaglercraft versions found");
ctx.close();
return;
}
if (eaglercraftVersions.contains(3)) {
eaglercraftVersion = 3;
}
count = data.readUnsignedShort(); // minecraft versions
final List<Integer> minecraftVersions = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
minecraftVersions.add(data.readUnsignedShort()); // minecraft version id
}
if (minecraftVersions.size() != 1) {
Logger.LOGGER.error("No supported minecraft versions found");
ctx.close();
}
minecraftVersion = minecraftVersions.get(0);
} else {
throw new IllegalArgumentException("Unknown Eaglercraft version: " + eaglercraftVersion);
}
final String clientBrand = data.readCharSequence(data.readUnsignedByte(), StandardCharsets.US_ASCII).toString(); // client brand
final String clientVersionString = data.readCharSequence(data.readUnsignedByte(), StandardCharsets.US_ASCII).toString(); // client version
if (eaglercraftVersion >= 2) {
data.skipBytes(1); // auth enabled
data.skipBytes(data.readUnsignedByte()); // auth username
}
if (data.isReadable()) {
throw new IllegalArgumentException("Too much data in packet: " + data.readableBytes() + " bytes");
}
Logger.LOGGER.info("Eaglercraft client connected: " + clientBrand + " " + clientVersionString);
final String serverBrand = "ViaProxy";
final String serverVersionString = ViaProxy.VERSION;
this.state = State.HANDSHAKE_COMPLETE;
this.version = VersionEnum.fromProtocolId(minecraftVersion);
if (this.version.equals(VersionEnum.UNKNOWN)) {
Logger.LOGGER.error("Unsupported protocol version: " + minecraftVersion);
ctx.close();
return;
}
final ByteBuf response = ctx.alloc().buffer();
response.writeByte(SERVER_VERSION); // packet id
if (eaglercraftVersion == 1) {
response.writeByte(1); // eaglercraft version
} else {
response.writeShort(eaglercraftVersion); // eaglercraft version
response.writeShort(minecraftVersion); // minecraft version
}
response.writeByte(serverBrand.length()).writeCharSequence(serverBrand, StandardCharsets.US_ASCII); // server brand
response.writeByte(serverVersionString.length()).writeCharSequence(serverVersionString, StandardCharsets.US_ASCII); // server version
response.writeByte(0); // auth method
response.writeShort(0); // salt length
ctx.writeAndFlush(new BinaryWebSocketFrame(response));
} else {
throw new IllegalStateException("Unexpected packet id " + packetId + " in state " + this.state);
}
break;
case HANDSHAKE_COMPLETE:
packetId = data.readUnsignedByte(); // packet id
if (packetId == CLIENT_REQUEST_LOGIN) {
final String username = data.readCharSequence(data.readUnsignedByte(), StandardCharsets.US_ASCII).toString(); // username
data.readCharSequence(data.readUnsignedByte(), StandardCharsets.US_ASCII).toString(); // requested server
data.skipBytes(data.readUnsignedByte()); // auth password
if (data.isReadable()) {
throw new IllegalArgumentException("Too much data in packet: " + data.readableBytes() + " bytes");
}
this.state = State.LOGIN;
this.username = username;
final UUID uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(StandardCharsets.UTF_8));
final ByteBuf response = ctx.alloc().buffer();
response.writeByte(SERVER_ALLOW_LOGIN); // packet id
response.writeByte(username.length()).writeCharSequence(username, StandardCharsets.US_ASCII); // username
response.writeLong(uuid.getMostSignificantBits()).writeLong(uuid.getLeastSignificantBits()); // uuid
ctx.writeAndFlush(new BinaryWebSocketFrame(response));
} else {
throw new IllegalStateException("Unexpected packet id " + packetId + " in state " + this.state);
}
break;
case LOGIN:
packetId = data.readUnsignedByte(); // packet id
if (packetId == CLIENT_PROFILE_DATA) {
final String type = data.readCharSequence(data.readUnsignedByte(), StandardCharsets.US_ASCII).toString();
final byte[] dataBytes = new byte[data.readUnsignedShort()];
data.readBytes(dataBytes);
if (data.isReadable()) {
throw new IllegalArgumentException("Too much data in packet: " + data.readableBytes() + " bytes");
}
} else if (packetId == CLIENT_FINISH_LOGIN) {
if (data.isReadable()) {
throw new IllegalArgumentException("Too much data in packet: " + data.readableBytes() + " bytes");
}
this.state = State.LOGIN_COMPLETE;
this.pluginMessageId = MCPackets.C2S_PLUGIN_MESSAGE.getId(this.version.getVersion());
if (this.pluginMessageId == -1) {
Logger.LOGGER.error("Unsupported protocol version: " + this.version.getVersion());
ctx.close();
return;
}
if (ctx.pipeline().get(Client2ProxyChannelInitializer.LEGACY_PASSTHROUGH_HANDLER_NAME) != null) {
ctx.pipeline().remove(Client2ProxyChannelInitializer.LEGACY_PASSTHROUGH_HANDLER_NAME);
}
out.add(this.writeHandshake(ctx.alloc().buffer(), ConnectionState.LOGIN));
final ByteBuf loginHello = ctx.alloc().buffer();
PacketTypes.writeVarInt(loginHello, ServerboundLoginPackets.HELLO.getId()); // packet id
PacketTypes.writeString(loginHello, this.username); // username
out.add(loginHello);
final ByteBuf response = ctx.alloc().buffer();
response.writeByte(SERVER_FINISH_LOGIN); // packet id
ctx.writeAndFlush(new BinaryWebSocketFrame(response));
} else {
throw new IllegalStateException("Unexpected packet id " + packetId + " in state " + this.state);
}
break;
case LOGIN_COMPLETE:
if (this.version.equals(VersionEnum.r1_5_2)) {
packetId = data.readUnsignedByte();
if (packetId == ServerboundPackets1_5_2.SHARED_KEY.getId()) {
ctx.channel().writeAndFlush(new BinaryWebSocketFrame(data.readerIndex(0).retain()));
break;
} else if (packetId == ServerboundPackets1_5_2.PLUGIN_MESSAGE.getId()) {
if (Types1_6_4.STRING.read(data).startsWith("EAG|")) {
break;
}
}
} else if (this.version.isNewerThanOrEqualTo(VersionEnum.r1_7_2tor1_7_5)) {
packetId = PacketTypes.readVarInt(data);
if (packetId == this.pluginMessageId) {
if (PacketTypes.readString(data, Short.MAX_VALUE).startsWith("EAG|")) {
break;
}
}
}
out.add(data.readerIndex(0).retain());
break;
default:
throw new IllegalStateException("Unexpected binary frame in state " + this.state);
}
} else if (in instanceof TextWebSocketFrame) {
final String text = ((TextWebSocketFrame) in).text();
if (this.state != State.PRE_HANDSHAKE) {
throw new IllegalStateException("Unexpected text frame in state " + this.state);
}
if (!text.equalsIgnoreCase("accept: motd")) {
ctx.close();
return;
}
this.state = State.STATUS;
this.version = VersionEnum.r1_8;
if (ctx.pipeline().get(Client2ProxyChannelInitializer.LEGACY_PASSTHROUGH_HANDLER_NAME) != null) {
ctx.pipeline().remove(Client2ProxyChannelInitializer.LEGACY_PASSTHROUGH_HANDLER_NAME);
}
out.add(this.writeHandshake(ctx.alloc().buffer(), ConnectionState.STATUS));
final ByteBuf statusRequest = ctx.alloc().buffer();
PacketTypes.writeVarInt(statusRequest, ServerboundStatusPackets.STATUS_REQUEST.getId()); // packet id
out.add(statusRequest);
} else {
throw new UnsupportedOperationException("Unsupported frame type: " + in.getClass().getName());
}
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) {
final WebSocketServerProtocolHandler.HandshakeComplete handshake = (WebSocketServerProtocolHandler.HandshakeComplete) evt;
if (!handshake.requestHeaders().contains("Host")) {
ctx.close();
return;
}
this.host = HostAndPort.fromString(handshake.requestHeaders().get("Host")).withDefaultPort(80);
}
super.userEventTriggered(ctx, evt);
}
private ByteBuf writeHandshake(final ByteBuf byteBuf, final ConnectionState state) {
PacketTypes.writeVarInt(byteBuf, ServerboundHandshakePackets.CLIENT_INTENTION.getId()); // packet id
PacketTypes.writeVarInt(byteBuf, this.version.getVersion()); // protocol version
PacketTypes.writeString(byteBuf, this.host.getHost()); // address
byteBuf.writeShort(this.host.getPort()); // port
PacketTypes.writeVarInt(byteBuf, state.getId()); // next state
return byteBuf;
}
public enum State {
STATUS,
PRE_HANDSHAKE,
HANDSHAKE,
HANDSHAKE_COMPLETE,
LOGIN,
LOGIN_COMPLETE,
}
}

View File

@ -1,83 +0,0 @@
/*
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.raphimc.viaproxy.proxy.client2proxy.eaglercraft;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import net.raphimc.viaproxy.proxy.client2proxy.Client2ProxyChannelInitializer;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.List;
public class EaglercraftInitialHandler extends ByteToMessageDecoder {
private static SslContext sslContext;
static {
final File certFolder = new File("certs");
if (certFolder.exists()) {
try {
sslContext = SslContextBuilder.forServer(new File(certFolder, "fullchain.pem"), new File(certFolder, "privkey.pem")).build();
} catch (Throwable e) {
throw new RuntimeException("Failed to load SSL context", e);
}
}
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
if (!ctx.channel().isOpen()) return;
if (!in.isReadable()) return;
if (in.readableBytes() >= 3 || in.getByte(0) != 'G') {
if (in.readableBytes() >= 3 && in.getCharSequence(0, 3, StandardCharsets.UTF_8).equals("GET")) { // Websocket request
if (sslContext != null) {
ctx.pipeline().addBefore(Client2ProxyChannelInitializer.EAGLERCRAFT_INITIAL_HANDLER_NAME, Client2ProxyChannelInitializer.WEBSOCKET_SSL_HANDLER_NAME, sslContext.newHandler(ctx.alloc()));
}
ctx.pipeline().addBefore(Client2ProxyChannelInitializer.EAGLERCRAFT_INITIAL_HANDLER_NAME, Client2ProxyChannelInitializer.WEBSOCKET_HTTP_CODEC_NAME, new HttpServerCodec());
ctx.pipeline().addBefore(Client2ProxyChannelInitializer.EAGLERCRAFT_INITIAL_HANDLER_NAME, Client2ProxyChannelInitializer.WEBSOCKET_HTTP_AGGREGATOR_NAME, new HttpObjectAggregator(65535, true));
ctx.pipeline().addBefore(Client2ProxyChannelInitializer.EAGLERCRAFT_INITIAL_HANDLER_NAME, Client2ProxyChannelInitializer.WEBSOCKET_COMPRESSION_NAME, new WebSocketServerCompressionHandler());
ctx.pipeline().addBefore(Client2ProxyChannelInitializer.EAGLERCRAFT_INITIAL_HANDLER_NAME, Client2ProxyChannelInitializer.WEBSOCKET_HANDLER_NAME, new WebSocketServerProtocolHandler("/", null, true));
ctx.pipeline().addBefore(Client2ProxyChannelInitializer.EAGLERCRAFT_INITIAL_HANDLER_NAME, Client2ProxyChannelInitializer.WEBSOCKET_ACTIVE_NOTIFIER_NAME, new WebSocketActiveNotifier());
ctx.pipeline().addBefore(Client2ProxyChannelInitializer.EAGLERCRAFT_INITIAL_HANDLER_NAME, Client2ProxyChannelInitializer.EAGLERCRAFT_HANDLER_NAME, new EaglercraftHandler());
ctx.fireUserEventTriggered(EaglercraftClientConnected.INSTANCE);
ctx.pipeline().fireChannelRead(in.readBytes(in.readableBytes()));
} else {
out.add(in.readBytes(in.readableBytes()));
}
ctx.pipeline().remove(this);
}
}
public static final class EaglercraftClientConnected {
public static final EaglercraftClientConnected INSTANCE = new EaglercraftClientConnected();
}
}

View File

@ -1,40 +0,0 @@
/*
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.raphimc.viaproxy.proxy.client2proxy.eaglercraft;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
public class WebSocketActiveNotifier extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) {
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) {
ctx.fireChannelActive();
ctx.pipeline().remove(this);
}
super.userEventTriggered(ctx, evt);
}
}

View File

@ -31,7 +31,6 @@ public class AdvancedTab extends AUITab {
JTextField proxy;
JCheckBox proxyOnlineMode;
JCheckBox legacySkinLoading;
JCheckBox eaglercraftSupport;
public AdvancedTab(final ViaProxyUI frame) {
super(frame, "Advanced");
@ -85,13 +84,6 @@ public class AdvancedTab extends AUITab {
ViaProxy.saveManager.uiSave.loadCheckBox("legacy_skin_loading", this.legacySkinLoading);
contentPane.add(this.legacySkinLoading);
}
{
this.eaglercraftSupport = new JCheckBox("Eaglercraft Support");
this.eaglercraftSupport.setBounds(10, 170, 465, 20);
this.eaglercraftSupport.setToolTipText("Enabling Eaglercraft Support allows Eaglercraft clients to connect to ViaProxy");
ViaProxy.saveManager.uiSave.loadCheckBox("eaglercraft_support", this.eaglercraftSupport);
contentPane.add(this.eaglercraftSupport);
}
}
@Override

View File

@ -203,7 +203,6 @@ public class GeneralTab extends AUITab {
final boolean betaCraftAuth = this.betaCraftAuth.isSelected();
final boolean proxyOnlineMode = ViaProxy.ui.advancedTab.proxyOnlineMode.isSelected();
final boolean legacySkinLoading = ViaProxy.ui.advancedTab.legacySkinLoading.isSelected();
final boolean eaglercraftSupport = ViaProxy.ui.advancedTab.eaglercraftSupport.isSelected();
final String proxyUrl = ViaProxy.ui.advancedTab.proxy.getText();
try {
@ -241,7 +240,6 @@ public class GeneralTab extends AUITab {
Options.PROTOCOL_VERSION = serverVersion;
Options.BETACRAFT_AUTH = betaCraftAuth;
Options.LEGACY_SKIN_LOADING = legacySkinLoading;
Options.ALLOW_EAGLERCRAFT_CLIENTS = eaglercraftSupport;
if (authMethod == 2) {
Options.OPENAUTHMOD_AUTH = true;