mirror of
https://github.com/ayunami2000/ayunViaProxyEagUtils.git
synced 2024-12-22 06:44:11 -08:00
Add nearly full Eaglercraft server support
TODO: finish making Eaglercraft 1.5 skins show up on Eaglercraft 1.8
This commit is contained in:
parent
8a154e833f
commit
a5eac20833
|
@ -10,5 +10,5 @@ repositories {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation files("libs/ViaProxy-3.0.21-SNAPSHOT+java8_PATCHED.jar")
|
||||
implementation files("libs/ViaProxy-3.0.22-SNAPSHOT+java8.jar")
|
||||
}
|
|
@ -0,0 +1,357 @@
|
|||
package me.ayunami2000.ayunViaProxyEagUtils;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.viaversion.viaversion.util.ChatColorUtil;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
|
||||
import io.netty.util.AttributeKey;
|
||||
import net.lenni0451.mcstructs.text.serializer.TextComponentSerializer;
|
||||
import net.raphimc.viaproxy.ViaProxy;
|
||||
import net.raphimc.viaproxy.proxy.session.ProxyConnection;
|
||||
import net.raphimc.viaproxy.util.logging.Logger;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022-2023 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
public class ConnectionHandshake {
|
||||
private static final AttributeKey<Integer> serverVersKey = AttributeKey.newInstance("eag-server-vers");
|
||||
private static final int protocolV2 = 2;
|
||||
private static final int protocolV3 = 3;
|
||||
|
||||
public static void attemptHandshake(List<Object> out, Channel ch, ProxyConnection proxyConnection, String password) {
|
||||
try {
|
||||
ByteArrayOutputStream bao = new ByteArrayOutputStream();
|
||||
DataOutputStream d = new DataOutputStream(bao);
|
||||
|
||||
d.writeByte(HandshakePacketTypes.PROTOCOL_CLIENT_VERSION);
|
||||
|
||||
d.writeByte(2); // legacy protocol version
|
||||
|
||||
d.writeShort(2); // supported eagler protocols count
|
||||
d.writeShort(protocolV2); // client supports v2
|
||||
d.writeShort(protocolV3); // client supports v3
|
||||
|
||||
d.writeShort(1); // supported game protocols count
|
||||
d.writeShort(proxyConnection.getServerVersion().getVersion()); // client supports this protocol
|
||||
|
||||
String clientBrand = "ViaProxy";
|
||||
d.writeByte(clientBrand.length());
|
||||
d.writeBytes(clientBrand);
|
||||
|
||||
String clientVers = ViaProxy.VERSION;
|
||||
d.writeByte(clientVers.length());
|
||||
d.writeBytes(clientVers);
|
||||
|
||||
d.writeBoolean(password != null);
|
||||
|
||||
String username = proxyConnection.getGameProfile().getName();
|
||||
d.writeByte(username.length());
|
||||
d.writeBytes(username);
|
||||
|
||||
out.add(new BinaryWebSocketFrame(ch.alloc().buffer(bao.size()).writeBytes(bao.toByteArray())));
|
||||
} catch (Throwable t) {
|
||||
Logger.LOGGER.error("Exception in handshake");
|
||||
Logger.LOGGER.error(t);
|
||||
}
|
||||
}
|
||||
|
||||
public static void attemptHandshake2(Channel ch, byte[] read, ProxyConnection proxyConnection, String password) {
|
||||
try {
|
||||
ByteArrayOutputStream bao = new ByteArrayOutputStream();
|
||||
DataOutputStream d = new DataOutputStream(bao);
|
||||
|
||||
String username = proxyConnection.getGameProfile().getName();
|
||||
|
||||
DataInputStream di = new DataInputStream(new ByteArrayInputStream(read));
|
||||
|
||||
int type = di.read();
|
||||
if (type == HandshakePacketTypes.PROTOCOL_VERSION_MISMATCH) {
|
||||
|
||||
StringBuilder protocols = new StringBuilder();
|
||||
int c = di.readShort();
|
||||
for (int i = 0; i < c; ++i) {
|
||||
if (i > 0) {
|
||||
protocols.append(", ");
|
||||
}
|
||||
protocols.append("v").append(di.readShort());
|
||||
}
|
||||
|
||||
StringBuilder games = new StringBuilder();
|
||||
c = di.readShort();
|
||||
for (int i = 0; i < c; ++i) {
|
||||
if (i > 0) {
|
||||
games.append(", ");
|
||||
}
|
||||
games.append("mc").append(di.readShort());
|
||||
}
|
||||
|
||||
Logger.LOGGER.info("Incompatible client: v2 & mc" + proxyConnection.getServerVersion().getVersion());
|
||||
Logger.LOGGER.info("Server supports: {}", protocols);
|
||||
Logger.LOGGER.info("Server supports: {}", games);
|
||||
|
||||
int msgLen = di.read();
|
||||
byte[] dat = new byte[msgLen];
|
||||
di.read(dat);
|
||||
String msg = new String(dat, StandardCharsets.UTF_8);
|
||||
|
||||
proxyConnection.kickClient(msg);
|
||||
} else if (type == HandshakePacketTypes.PROTOCOL_SERVER_VERSION) {
|
||||
int serverVers = di.readShort();
|
||||
|
||||
if (serverVers != protocolV2 && serverVers != protocolV3) {
|
||||
Logger.LOGGER.info("Incompatible server version: {}", serverVers);
|
||||
proxyConnection.kickClient(serverVers < protocolV2 ? "Outdated Server" : "Outdated Client");
|
||||
return;
|
||||
}
|
||||
|
||||
ch.attr(serverVersKey).set(serverVers);
|
||||
|
||||
int gameVers = di.readShort();
|
||||
if (gameVers != proxyConnection.getServerVersion().getVersion()) {
|
||||
Logger.LOGGER.info("Incompatible minecraft protocol version: {}", gameVers);
|
||||
proxyConnection.kickClient("This server does not support " + proxyConnection.getServerVersion().getName() + "!");
|
||||
return;
|
||||
}
|
||||
|
||||
Logger.LOGGER.info("Server protocol: {}", serverVers);
|
||||
|
||||
int msgLen = di.read();
|
||||
byte[] dat = new byte[msgLen];
|
||||
di.read(dat);
|
||||
String brandStr = asciiString(dat);
|
||||
|
||||
msgLen = di.read();
|
||||
dat = new byte[msgLen];
|
||||
di.read(dat);
|
||||
String versionStr = asciiString(dat);
|
||||
|
||||
Logger.LOGGER.info("Server version: {}", versionStr);
|
||||
Logger.LOGGER.info("Server brand: {}", brandStr);
|
||||
|
||||
int authType = di.read();
|
||||
int saltLength = (int) di.readShort() & 0xFFFF;
|
||||
|
||||
byte[] salt = new byte[saltLength];
|
||||
di.read(salt);
|
||||
|
||||
bao.reset();
|
||||
d.writeByte(HandshakePacketTypes.PROTOCOL_CLIENT_REQUEST_LOGIN);
|
||||
|
||||
d.writeByte(username.length());
|
||||
d.writeBytes(username);
|
||||
|
||||
String requestedServer = "default";
|
||||
d.writeByte(requestedServer.length());
|
||||
d.writeBytes(requestedServer);
|
||||
|
||||
if (authType != 0 && password != null && !password.isEmpty()) {
|
||||
if (authType == HandshakePacketTypes.AUTH_METHOD_PLAINTEXT) {
|
||||
Logger.LOGGER.warn("Server is using insecure plaintext authentication");
|
||||
d.writeByte(password.length() << 1);
|
||||
d.writeChars(password);
|
||||
} else if (authType == HandshakePacketTypes.AUTH_METHOD_EAGLER_SHA256) {
|
||||
SHA256Digest digest = new SHA256Digest();
|
||||
|
||||
int passLen = password.length();
|
||||
|
||||
digest.update((byte) ((passLen >> 8) & 0xFF));
|
||||
digest.update((byte) (passLen & 0xFF));
|
||||
|
||||
for (int i = 0; i < passLen; ++i) {
|
||||
char codePoint = password.charAt(i);
|
||||
digest.update((byte) ((codePoint >> 8) & 0xFF));
|
||||
digest.update((byte) (codePoint & 0xFF));
|
||||
}
|
||||
|
||||
digest.update(HandshakePacketTypes.EAGLER_SHA256_SALT_SAVE, 0, 32);
|
||||
|
||||
byte[] hashed = new byte[32];
|
||||
digest.doFinal(hashed, 0);
|
||||
|
||||
digest.reset();
|
||||
|
||||
digest.update(hashed, 0, 32);
|
||||
digest.update(salt, 0, 32);
|
||||
digest.update(HandshakePacketTypes.EAGLER_SHA256_SALT_BASE, 0, 32);
|
||||
|
||||
digest.doFinal(hashed, 0);
|
||||
|
||||
digest.reset();
|
||||
|
||||
digest.update(hashed, 0, 32);
|
||||
digest.update(salt, 32, 32);
|
||||
digest.update(HandshakePacketTypes.EAGLER_SHA256_SALT_BASE, 0, 32);
|
||||
|
||||
digest.doFinal(hashed, 0);
|
||||
|
||||
d.writeByte(32);
|
||||
d.write(hashed);
|
||||
} else if (authType == HandshakePacketTypes.AUTH_METHOD_AUTHME_SHA256) {
|
||||
SHA256Digest digest = new SHA256Digest();
|
||||
|
||||
byte[] passwd = password.getBytes(StandardCharsets.UTF_8);
|
||||
digest.update(passwd, 0, passwd.length);
|
||||
|
||||
byte[] hashed = new byte[32];
|
||||
digest.doFinal(hashed, 0);
|
||||
|
||||
byte[] toHexAndSalt = new byte[64];
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
toHexAndSalt[i << 1] = HEX[(hashed[i] >> 4) & 0xF];
|
||||
toHexAndSalt[(i << 1) + 1] = HEX[hashed[i] & 0xF];
|
||||
}
|
||||
|
||||
digest.reset();
|
||||
digest.update(toHexAndSalt, 0, 64);
|
||||
digest.update(salt, 0, salt.length);
|
||||
|
||||
digest.doFinal(hashed, 0);
|
||||
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
toHexAndSalt[i << 1] = HEX[(hashed[i] >> 4) & 0xF];
|
||||
toHexAndSalt[(i << 1) + 1] = HEX[hashed[i] & 0xF];
|
||||
}
|
||||
|
||||
d.writeByte(64);
|
||||
d.write(toHexAndSalt);
|
||||
} else {
|
||||
Logger.LOGGER.error("Unsupported authentication type: {}", authType);
|
||||
proxyConnection.kickClient(ChatColorUtil.COLOR_CHAR + "cUnsupported authentication type: " + authType + "\n\n" + ChatColorUtil.COLOR_CHAR + "7(Use a newer version of the client)");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
d.writeByte(0);
|
||||
}
|
||||
|
||||
ch.writeAndFlush(new BinaryWebSocketFrame(ch.alloc().buffer(bao.size()).writeBytes(bao.toByteArray())));
|
||||
} else if (type == HandshakePacketTypes.PROTOCOL_SERVER_ERROR) {
|
||||
showError(proxyConnection, di, true);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
Logger.LOGGER.error("Exception in handshake");
|
||||
Logger.LOGGER.error(t);
|
||||
}
|
||||
}
|
||||
|
||||
public static void attemptHandshake3(Channel ch, byte[] read, ProxyConnection proxyConnection) {
|
||||
try {
|
||||
int serverVers = ch.attr(serverVersKey).get();
|
||||
|
||||
ByteArrayOutputStream bao = new ByteArrayOutputStream();
|
||||
DataOutputStream d = new DataOutputStream(bao);
|
||||
|
||||
int msgLen;
|
||||
byte[] dat;
|
||||
|
||||
DataInputStream di = new DataInputStream(new ByteArrayInputStream(read));
|
||||
int type = di.read();
|
||||
if (type == HandshakePacketTypes.PROTOCOL_SERVER_ALLOW_LOGIN) {
|
||||
msgLen = di.read();
|
||||
dat = new byte[msgLen];
|
||||
di.read(dat);
|
||||
|
||||
String serverUsername = asciiString(dat);
|
||||
|
||||
JsonObject json = new JsonObject();
|
||||
json.addProperty("name", serverUsername);
|
||||
UUID uuid = new UUID(di.readLong(), di.readLong());
|
||||
json.addProperty("uuid", uuid.toString());
|
||||
proxyConnection.setGameProfile(new GameProfile(uuid, serverUsername));
|
||||
|
||||
if (proxyConnection.getC2P().hasAttr(EaglercraftHandler.profileDataKey)) {
|
||||
EaglercraftHandler.ProfileData profileData = proxyConnection.getC2P().attr(EaglercraftHandler.profileDataKey).get();
|
||||
bao.reset();
|
||||
d.writeByte(HandshakePacketTypes.PROTOCOL_CLIENT_PROFILE_DATA);
|
||||
d.writeByte(profileData.type.length());
|
||||
d.writeBytes(profileData.type);
|
||||
d.writeShort(profileData.data.length);
|
||||
d.write(profileData.data);
|
||||
ch.writeAndFlush(new BinaryWebSocketFrame(ch.alloc().buffer(bao.size()).writeBytes(bao.toByteArray())));
|
||||
}
|
||||
|
||||
bao.reset();
|
||||
d.writeByte(HandshakePacketTypes.PROTOCOL_CLIENT_FINISH_LOGIN);
|
||||
ch.writeAndFlush(new BinaryWebSocketFrame(ch.alloc().buffer(bao.size()).writeBytes(bao.toByteArray())));
|
||||
} else if (type == HandshakePacketTypes.PROTOCOL_SERVER_DENY_LOGIN) {
|
||||
if (serverVers == protocolV2) {
|
||||
msgLen = di.read();
|
||||
} else {
|
||||
msgLen = di.readUnsignedShort();
|
||||
}
|
||||
dat = new byte[msgLen];
|
||||
di.read(dat);
|
||||
String errStr = new String(dat, StandardCharsets.UTF_8);
|
||||
proxyConnection.kickClient(TextComponentSerializer.V1_8.deserialize(errStr).asLegacyFormatString());
|
||||
} else if (type == HandshakePacketTypes.PROTOCOL_SERVER_ERROR) {
|
||||
showError(proxyConnection, di, serverVers == protocolV2);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
Logger.LOGGER.error("Exception in handshake");
|
||||
Logger.LOGGER.error(t);
|
||||
}
|
||||
}
|
||||
|
||||
public static void attemptHandshake4(Channel ch, byte[] read, ProxyConnection proxyConnection) {
|
||||
try {
|
||||
int serverVers = ch.attr(serverVersKey).get();
|
||||
|
||||
DataInputStream di = new DataInputStream(new ByteArrayInputStream(read));
|
||||
int type = di.read();
|
||||
if (type == HandshakePacketTypes.PROTOCOL_SERVER_ERROR) {
|
||||
showError(proxyConnection, di, serverVers == protocolV2);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
Logger.LOGGER.error("Exception in handshake");
|
||||
Logger.LOGGER.error(t);
|
||||
}
|
||||
}
|
||||
|
||||
private static void showError(ProxyConnection proxyConnection, DataInputStream err, boolean v2) throws IOException {
|
||||
int errorCode = err.read();
|
||||
int msgLen = v2 ? err.read() : err.readUnsignedShort();
|
||||
byte[] dat = new byte[msgLen];
|
||||
err.read(dat);
|
||||
String errStr = new String(dat, StandardCharsets.UTF_8);
|
||||
Logger.LOGGER.info("Server Error Code {}: {}", errorCode, errStr);
|
||||
if(errorCode == HandshakePacketTypes.SERVER_ERROR_RATELIMIT_BLOCKED) {
|
||||
proxyConnection.kickClient("Server Error Ratelimited (blocked)");
|
||||
}else if(errorCode == HandshakePacketTypes.SERVER_ERROR_RATELIMIT_LOCKED) {
|
||||
proxyConnection.kickClient("Server Error Ratelimited (locked)");
|
||||
}else if(errorCode == HandshakePacketTypes.SERVER_ERROR_CUSTOM_MESSAGE) {
|
||||
proxyConnection.kickClient("Server Error Message " + TextComponentSerializer.V1_8.deserialize(errStr).asLegacyFormatString());
|
||||
}else if(errorCode == HandshakePacketTypes.SERVER_ERROR_AUTHENTICATION_REQUIRED) {
|
||||
proxyConnection.kickClient("Server Error Authentication required " + TextComponentSerializer.V1_8.deserialize(errStr).asLegacyFormatString());
|
||||
}else {
|
||||
proxyConnection.kickClient("Server Error Code " + errorCode + "\n" + TextComponentSerializer.V1_8.deserialize(errStr).asLegacyFormatString());
|
||||
}
|
||||
}
|
||||
|
||||
private static final byte[] HEX = new byte[]{
|
||||
(byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', (byte) '7',
|
||||
(byte) '8', (byte) '9', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f'
|
||||
};
|
||||
|
||||
public static String asciiString(byte[] bytes) {
|
||||
char[] str = new char[bytes.length];
|
||||
for(int i = 0; i < bytes.length; ++i) {
|
||||
str[i] = (char)((int) bytes[i] & 0xFF);
|
||||
}
|
||||
return new String(str);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,291 @@
|
|||
package me.ayunami2000.ayunViaProxyEagUtils;
|
||||
|
||||
import com.google.common.primitives.Ints;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.handler.codec.MessageToMessageCodec;
|
||||
import io.netty.handler.codec.http.websocketx.*;
|
||||
import net.raphimc.netminecraft.constants.MCPackets;
|
||||
import net.raphimc.netminecraft.netty.connection.NetClient;
|
||||
import net.raphimc.netminecraft.packet.PacketTypes;
|
||||
import net.raphimc.vialegacy.protocols.release.protocol1_6_1to1_5_2.ClientboundPackets1_5_2;
|
||||
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.vialoader.util.VersionEnum;
|
||||
import net.raphimc.viaproxy.proxy.session.ProxyConnection;
|
||||
import net.raphimc.viaproxy.proxy.util.ExceptionUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
public class EaglerServerHandler extends MessageToMessageCodec<BinaryWebSocketFrame, ByteBuf> {
|
||||
private final VersionEnum version;
|
||||
private final String password;
|
||||
private final NetClient proxyConnection;
|
||||
private final Map<UUID, String> uuidStringMap = new HashMap<>();
|
||||
private final List<UUID> skinsBeingFetched = new ArrayList<>();
|
||||
private ByteBuf serverBoundPartialPacket = Unpooled.EMPTY_BUFFER;
|
||||
private ByteBuf clientBoundPartialPacket = Unpooled.EMPTY_BUFFER;
|
||||
public EaglerServerHandler(NetClient proxyConnection, String password) {
|
||||
this.version = proxyConnection instanceof ProxyConnection ? ((ProxyConnection) proxyConnection).getServerVersion() : VersionEnum.r1_5_2;
|
||||
this.password = password;
|
||||
this.proxyConnection = proxyConnection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||
ExceptionUtil.handleNettyException(ctx, cause, null);
|
||||
}
|
||||
|
||||
private int handshakeState = 0;
|
||||
|
||||
@Override
|
||||
public void encode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
|
||||
if (version.isNewerThan(VersionEnum.r1_6_4)) {
|
||||
if (handshakeState == 0) {
|
||||
handshakeState = 1;
|
||||
if (((ProxyConnection) proxyConnection).getGameProfile() == null) {
|
||||
out.add(Unpooled.EMPTY_BUFFER);
|
||||
ctx.close();
|
||||
return;
|
||||
}
|
||||
ConnectionHandshake.attemptHandshake(out, ctx.channel(), (ProxyConnection) proxyConnection, password);
|
||||
if (out.isEmpty()) {
|
||||
out.add(Unpooled.EMPTY_BUFFER);
|
||||
}
|
||||
} else if (handshakeState < 4) {
|
||||
out.add(Unpooled.EMPTY_BUFFER);
|
||||
} else {
|
||||
out.add(new BinaryWebSocketFrame(in.retain()));
|
||||
}
|
||||
} else {
|
||||
ByteBuf bb = ctx.alloc().buffer(serverBoundPartialPacket.readableBytes() + in.readableBytes());
|
||||
bb.writeBytes(serverBoundPartialPacket);
|
||||
serverBoundPartialPacket.release();
|
||||
serverBoundPartialPacket = Unpooled.EMPTY_BUFFER;
|
||||
bb.writeBytes(in);
|
||||
int readerIndex = 0;
|
||||
try {
|
||||
while (bb.isReadable()) {
|
||||
readerIndex = bb.readerIndex();
|
||||
ServerboundPackets1_5_2 pkt = ServerboundPackets1_5_2.getPacket(bb.readUnsignedByte());
|
||||
pkt.getPacketReader().accept(null, bb);
|
||||
int len = bb.readerIndex() - readerIndex;
|
||||
ByteBuf packet = ctx.alloc().buffer(len);
|
||||
bb.readerIndex(readerIndex);
|
||||
bb.readBytes(packet, len);
|
||||
encodeOld(ctx, packet, out);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
bb.readerIndex(readerIndex);
|
||||
if (bb.readableBytes() > 65535) {
|
||||
ctx.close();
|
||||
out.add(Unpooled.EMPTY_BUFFER);
|
||||
return;
|
||||
}
|
||||
serverBoundPartialPacket = ctx.alloc().buffer(bb.readableBytes());
|
||||
serverBoundPartialPacket.writeBytes(bb);
|
||||
}
|
||||
}
|
||||
if (out.isEmpty()) {
|
||||
out.add(Unpooled.EMPTY_BUFFER);
|
||||
}
|
||||
}
|
||||
|
||||
public void encodeOld(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
|
||||
if (handshakeState == 0) {
|
||||
handshakeState = 1;
|
||||
if (in.readableBytes() >= 2 && in.getUnsignedByte(0) == 2) {
|
||||
in.setByte(1, in.getUnsignedByte(1) + 8);
|
||||
}
|
||||
}
|
||||
if (in.readableBytes() >= 1 && in.getUnsignedByte(0) == 0xFD) {
|
||||
return;
|
||||
}
|
||||
if (in.readableBytes() >= 3 && in.getUnsignedByte(0) == 250) {
|
||||
in.skipBytes(1);
|
||||
String tag;
|
||||
byte[] msg;
|
||||
try {
|
||||
tag = Types1_6_4.STRING.read(in);
|
||||
if (tag.equals("EAG|Skins-1.8")) {
|
||||
msg = new byte[in.readShort()];
|
||||
in.readBytes(msg);
|
||||
if (msg.length == 0) {
|
||||
throw new IOException("Zero-length packet recieved");
|
||||
}
|
||||
final int packetId = msg[0] & 0xFF;
|
||||
switch (packetId) {
|
||||
case 3: {
|
||||
if (msg.length != 17) {
|
||||
throw new IOException("Invalid length " + msg.length + " for skin request packet");
|
||||
}
|
||||
final UUID searchUUID = SkinPackets.bytesToUUID(msg, 1);
|
||||
if (uuidStringMap.containsKey(searchUUID)) {
|
||||
// skinsBeingFetched.add(searchUUID);
|
||||
String name = uuidStringMap.get(searchUUID);
|
||||
ByteBuf bb = ctx.alloc().buffer();
|
||||
bb.writeByte((byte) 250);
|
||||
Types1_6_4.STRING.write(bb, "EAG|FetchSkin"); // todo: get to work
|
||||
bb.writeByte((byte) 0);
|
||||
bb.writeByte((byte) 0);
|
||||
bb.writeBytes(name.getBytes(StandardCharsets.UTF_8));
|
||||
out.add(new BinaryWebSocketFrame(bb));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 6: {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new IOException("Unknown packet type " + packetId);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
in.resetReaderIndex();
|
||||
}
|
||||
out.add(new BinaryWebSocketFrame(in.retain()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ChannelHandlerContext ctx, BinaryWebSocketFrame in, List<Object> out) {
|
||||
if (version.isNewerThan(VersionEnum.r1_6_4)) {
|
||||
if (handshakeState == 0) {
|
||||
out.add(Unpooled.EMPTY_BUFFER);
|
||||
} else if (handshakeState == 1) {
|
||||
handshakeState = 2;
|
||||
ConnectionHandshake.attemptHandshake2(ctx.channel(), ByteBufUtil.getBytes(in.content()), (ProxyConnection) proxyConnection, password);
|
||||
out.add(Unpooled.EMPTY_BUFFER);
|
||||
} else if (handshakeState == 2) {
|
||||
handshakeState = 3;
|
||||
ConnectionHandshake.attemptHandshake3(ctx.channel(), ByteBufUtil.getBytes(in.content()), (ProxyConnection) proxyConnection);
|
||||
ByteBuf bb = ctx.alloc().buffer();
|
||||
PacketTypes.writeVarInt(bb, MCPackets.S2C_LOGIN_SUCCESS.getId(version.getVersion()));
|
||||
PacketTypes.writeString(bb, ((ProxyConnection) proxyConnection).getGameProfile().getId().toString());
|
||||
PacketTypes.writeString(bb, ((ProxyConnection) proxyConnection).getGameProfile().getName());
|
||||
out.add(bb);
|
||||
} else if (handshakeState == 3) {
|
||||
handshakeState = 4;
|
||||
ConnectionHandshake.attemptHandshake4(ctx.channel(), ByteBufUtil.getBytes(in.content()), (ProxyConnection) proxyConnection);
|
||||
out.add(Unpooled.EMPTY_BUFFER);
|
||||
} else {
|
||||
if (in.content().getByte(0) == MCPackets.S2C_LOGIN_SUCCESS.getId(version.getVersion()) && in.content().getByte(1) == 0 && in.content().getByte(2) == 2) {
|
||||
out.add(Unpooled.EMPTY_BUFFER);
|
||||
return;
|
||||
}
|
||||
if (in.content().getByte(0) == 0) {
|
||||
in.content().skipBytes(1);
|
||||
PacketTypes.readVarInt(in.content());
|
||||
if (in.content().readableBytes() > 0) {
|
||||
in.content().setByte(0, 0x40);
|
||||
}
|
||||
in.content().resetReaderIndex();
|
||||
}
|
||||
out.add(in.content().retain());
|
||||
}
|
||||
} else {
|
||||
ByteBuf bb = ctx.alloc().buffer(clientBoundPartialPacket.readableBytes() + in.content().readableBytes());
|
||||
bb.writeBytes(clientBoundPartialPacket);
|
||||
clientBoundPartialPacket.release();
|
||||
clientBoundPartialPacket = Unpooled.EMPTY_BUFFER;
|
||||
bb.writeBytes(in.content());
|
||||
int readerIndex = 0;
|
||||
try {
|
||||
while (bb.isReadable()) {
|
||||
readerIndex = bb.readerIndex();
|
||||
ClientboundPackets1_5_2 pkt = ClientboundPackets1_5_2.getPacket(bb.readUnsignedByte());
|
||||
pkt.getPacketReader().accept(null, bb);
|
||||
int len = bb.readerIndex() - readerIndex;
|
||||
ByteBuf packet = ctx.alloc().buffer(len);
|
||||
bb.readerIndex(readerIndex);
|
||||
bb.readBytes(packet, len);
|
||||
decodeOld(ctx, packet, out);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
bb.readerIndex(readerIndex);
|
||||
if (bb.readableBytes() > 65535) {
|
||||
ctx.close();
|
||||
out.add(Unpooled.EMPTY_BUFFER);
|
||||
return;
|
||||
}
|
||||
clientBoundPartialPacket = ctx.alloc().buffer(bb.readableBytes());
|
||||
clientBoundPartialPacket.writeBytes(bb);
|
||||
}
|
||||
}
|
||||
if (out.isEmpty()) {
|
||||
out.add(Unpooled.EMPTY_BUFFER);
|
||||
}
|
||||
}
|
||||
public void decodeOld(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
|
||||
if (in.getUnsignedByte(0) == 0x14) {
|
||||
in.skipBytes(5);
|
||||
try {
|
||||
String name = Types1_6_4.STRING.read(in);
|
||||
UUID uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8));
|
||||
uuidStringMap.put(uuid, name);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
in.resetReaderIndex();
|
||||
}
|
||||
if (in.getUnsignedByte(0) == 0xFD) {
|
||||
in.writerIndex(0);
|
||||
in.writeByte((byte) 0xCD);
|
||||
in.writeByte((byte) 0x00);
|
||||
ctx.writeAndFlush(new BinaryWebSocketFrame(in.retain()));
|
||||
return;
|
||||
}
|
||||
if (!skinsBeingFetched.isEmpty() && in.readableBytes() >= 3 && in.getUnsignedByte(0) == 250) {
|
||||
in.skipBytes(1);
|
||||
String tag;
|
||||
byte[] msg;
|
||||
try {
|
||||
tag = Types1_6_4.STRING.read(in);
|
||||
// System.out.println(tag);
|
||||
if (tag.equals("EAG|UserSkin")) {
|
||||
msg = new byte[in.readShort()];
|
||||
in.readBytes(msg);
|
||||
System.out.println(msg.length);
|
||||
byte[] res = new byte[msg.length - 1];
|
||||
System.arraycopy(msg, 1, res, 0, res.length);
|
||||
if (res.length == 8192) {
|
||||
final int[] tmp1 = new int[2048];
|
||||
final int[] tmp2 = new int[4096];
|
||||
for (int i = 0; i < tmp1.length; ++i) {
|
||||
tmp1[i] = Ints.fromBytes(res[i * 4 + 3], res[i * 4], res[i * 4 + 1], res[i * 4 + 2]);
|
||||
}
|
||||
SkinConverter.convert64x32to64x64(tmp1, tmp2);
|
||||
res = new byte[16384];
|
||||
for (int i = 0; i < tmp2.length; ++i) {
|
||||
System.arraycopy(Ints.toByteArray(tmp2[i]), 0, res, i * 4, 4);
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < res.length; j += 4) {
|
||||
final byte tmp3 = res[j + 3];
|
||||
res[j + 3] = res[j + 2];
|
||||
res[j + 2] = res[j + 1];
|
||||
res[j + 1] = res[j];
|
||||
res[j] = tmp3;
|
||||
}
|
||||
}
|
||||
in.writerIndex(1);
|
||||
Types1_6_4.STRING.write(in, "EAG|Skins-1.8");
|
||||
byte[] data = SkinPackets.makeCustomResponse(skinsBeingFetched.remove(0), 0, res);
|
||||
in.writeShort(data.length);
|
||||
in.writeBytes(data);
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
in.resetReaderIndex();
|
||||
}
|
||||
if (in.getByte(0) == (byte) 0x83 && in.getShort(1) != 358) {
|
||||
return;
|
||||
}
|
||||
out.add(in.retain());
|
||||
}
|
||||
}
|
|
@ -77,6 +77,10 @@ public class EaglerSkinHandler extends ChannelInboundHandlerAdapter {
|
|||
}
|
||||
try {
|
||||
if ("EAG|MySkin".equals(tag)) {
|
||||
if (!FunnyConfig.eaglerSkins) {
|
||||
bb.release();
|
||||
return;
|
||||
}
|
||||
if (!EaglerSkinHandler.skinCollection.containsKey(uuid)) {
|
||||
final int t = msg[0] & 0xFF;
|
||||
if (t < EaglerSkinHandler.SKIN_DATA_SIZE.length && msg.length == EaglerSkinHandler.SKIN_DATA_SIZE[t] + 1) {
|
||||
|
@ -87,6 +91,10 @@ public class EaglerSkinHandler extends ChannelInboundHandlerAdapter {
|
|||
return;
|
||||
}
|
||||
if ("EAG|MyCape".equals(tag)) {
|
||||
if (!FunnyConfig.eaglerSkins) {
|
||||
bb.release();
|
||||
return;
|
||||
}
|
||||
if (!EaglerSkinHandler.capeCollection.containsKey(uuid)) {
|
||||
final int t = msg[0] & 0xFF;
|
||||
if (t < EaglerSkinHandler.CAPE_DATA_SIZE.length && msg.length == EaglerSkinHandler.CAPE_DATA_SIZE[t] + 2) {
|
||||
|
@ -113,7 +121,7 @@ public class EaglerSkinHandler extends ChannelInboundHandlerAdapter {
|
|||
conc = conc2;
|
||||
}
|
||||
sendData(ctx, "EAG|UserSkin", conc);
|
||||
} else if (EaglerXSkinHandler.skinService.loadPremiumSkins) {
|
||||
} else if (FunnyConfig.premiumSkins) {
|
||||
try {
|
||||
URL url = new URL("https://playerdb.co/api/player/minecraft/" + fetch);
|
||||
URLConnection urlConnection = url.openConnection();
|
||||
|
|
|
@ -78,6 +78,10 @@ public class EaglerVoiceHandler extends ChannelInboundHandlerAdapter {
|
|||
super.channelRead(ctx, obj);
|
||||
return;
|
||||
}
|
||||
if (!FunnyConfig.eaglerVoice) {
|
||||
bb.release();
|
||||
return;
|
||||
}
|
||||
final DataInputStream streamIn = new DataInputStream(new ByteArrayInputStream(msg));
|
||||
final int sig = streamIn.read();
|
||||
switch (sig) {
|
||||
|
|
|
@ -13,7 +13,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
|
||||
public class EaglerXSkinHandler extends ChannelInboundHandlerAdapter {
|
||||
private final ConcurrentHashMap<String, byte[]> profileData;
|
||||
public static final SkinService skinService;
|
||||
public static SkinService skinService;
|
||||
private String user;
|
||||
private int pluginMessageId;
|
||||
|
||||
|
@ -63,15 +63,17 @@ public class EaglerXSkinHandler extends ChannelInboundHandlerAdapter {
|
|||
}
|
||||
if (this.user == null) {
|
||||
this.user = ((EaglercraftHandler) ctx.pipeline().get("eaglercraft-handler")).username;
|
||||
final UUID clientUUID = UUID.nameUUIDFromBytes(("OfflinePlayer:" + this.user).getBytes(StandardCharsets.UTF_8));
|
||||
if (this.profileData.containsKey("skin_v1")) {
|
||||
try {
|
||||
SkinPackets.registerEaglerPlayer(clientUUID, this.profileData.get("skin_v1"), EaglerXSkinHandler.skinService);
|
||||
} catch (Throwable ex) {
|
||||
if (FunnyConfig.eaglerSkins) {
|
||||
final UUID clientUUID = UUID.nameUUIDFromBytes(("OfflinePlayer:" + this.user).getBytes(StandardCharsets.UTF_8));
|
||||
if (this.profileData.containsKey("skin_v1")) {
|
||||
try {
|
||||
SkinPackets.registerEaglerPlayer(clientUUID, this.profileData.get("skin_v1"), EaglerXSkinHandler.skinService);
|
||||
} catch (Throwable ex) {
|
||||
SkinPackets.registerEaglerPlayerFallback(clientUUID, EaglerXSkinHandler.skinService);
|
||||
}
|
||||
} else {
|
||||
SkinPackets.registerEaglerPlayerFallback(clientUUID, EaglerXSkinHandler.skinService);
|
||||
}
|
||||
} else {
|
||||
SkinPackets.registerEaglerPlayerFallback(clientUUID, EaglerXSkinHandler.skinService);
|
||||
}
|
||||
}
|
||||
if (this.pluginMessageId <= 0) {
|
||||
|
@ -101,8 +103,4 @@ public class EaglerXSkinHandler extends ChannelInboundHandlerAdapter {
|
|||
EaglerXSkinHandler.skinService.unregisterPlayer(UUID.nameUUIDFromBytes(("OfflinePlayer:" + this.user).getBytes(StandardCharsets.UTF_8)));
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
skinService = new SkinService();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ 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 io.netty.util.AttributeKey;
|
||||
import net.lenni0451.mcstructs.text.serializer.TextComponentSerializer;
|
||||
import net.raphimc.netminecraft.constants.ConnectionState;
|
||||
import net.raphimc.netminecraft.constants.MCPackets;
|
||||
|
@ -24,6 +25,7 @@ import net.raphimc.vialegacy.protocols.release.protocol1_6_1to1_5_2.ServerboundP
|
|||
import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.types.Types1_6_4;
|
||||
import net.raphimc.vialoader.util.VersionEnum;
|
||||
import net.raphimc.viaproxy.ViaProxy;
|
||||
import net.raphimc.viaproxy.proxy.client2proxy.Client2ProxyChannelInitializer;
|
||||
import net.raphimc.viaproxy.proxy.util.ExceptionUtil;
|
||||
import net.raphimc.viaproxy.util.logging.Logger;
|
||||
|
||||
|
@ -38,6 +40,15 @@ import java.util.List;
|
|||
import java.util.UUID;
|
||||
|
||||
public class EaglercraftHandler extends MessageToMessageCodec<WebSocketFrame, ByteBuf> {
|
||||
public static class ProfileData {
|
||||
public final String type;
|
||||
public final byte[] data;
|
||||
public ProfileData(String type, byte[] data) {
|
||||
this.type = type;
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
public static final AttributeKey<ProfileData> profileDataKey = AttributeKey.newInstance("eagx-profile-data");
|
||||
private HostAndPort host;
|
||||
public State state;
|
||||
public VersionEnum version;
|
||||
|
@ -50,7 +61,9 @@ public class EaglercraftHandler extends MessageToMessageCodec<WebSocketFrame, By
|
|||
|
||||
public void channelActive(final ChannelHandlerContext ctx) throws Exception {
|
||||
ctx.channel().attr(MCPipeline.COMPRESSION_THRESHOLD_ATTRIBUTE_KEY).set(-2);
|
||||
ctx.pipeline().remove("sizer");
|
||||
if (ctx.pipeline().get(MCPipeline.SIZER_HANDLER_NAME) != null) {
|
||||
ctx.pipeline().remove(MCPipeline.SIZER_HANDLER_NAME);
|
||||
}
|
||||
super.channelActive(ctx);
|
||||
}
|
||||
|
||||
|
@ -224,12 +237,13 @@ public class EaglercraftHandler extends MessageToMessageCodec<WebSocketFrame, By
|
|||
case LOGIN: {
|
||||
final int packetId = data.readUnsignedByte();
|
||||
if (packetId == 7) {
|
||||
data.readCharSequence(data.readUnsignedByte(), StandardCharsets.US_ASCII);
|
||||
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");
|
||||
}
|
||||
ctx.channel().attr(profileDataKey).set(new ProfileData(type, dataBytes));
|
||||
} else {
|
||||
if (packetId != 8) {
|
||||
throw new IllegalStateException("Unexpected packet id " + packetId + " in state " + this.state);
|
||||
|
@ -244,8 +258,8 @@ public class EaglercraftHandler extends MessageToMessageCodec<WebSocketFrame, By
|
|||
ctx.close();
|
||||
return;
|
||||
}
|
||||
if (ctx.pipeline().get("legacy-passthrough-handler") != null) {
|
||||
ctx.pipeline().remove("legacy-passthrough-handler");
|
||||
if (ctx.pipeline().get(Client2ProxyChannelInitializer.LEGACY_PASSTHROUGH_INITIAL_HANDLER_NAME) != null) {
|
||||
ctx.pipeline().remove(Client2ProxyChannelInitializer.LEGACY_PASSTHROUGH_INITIAL_HANDLER_NAME);
|
||||
}
|
||||
out.add(this.writeHandshake(ctx.alloc().buffer(), ConnectionState.LOGIN));
|
||||
final ByteBuf loginHello = ctx.alloc().buffer();
|
||||
|
@ -265,10 +279,12 @@ public class EaglercraftHandler extends MessageToMessageCodec<WebSocketFrame, By
|
|||
ctx.channel().writeAndFlush(new BinaryWebSocketFrame(data.readerIndex(0).retain()));
|
||||
break;
|
||||
}
|
||||
if (packetId == ServerboundPackets1_5_2.PLUGIN_MESSAGE.getId() && Types1_6_4.STRING.read(data).startsWith("EAG|")) {
|
||||
break;
|
||||
if (!ctx.channel().hasAttr(Main.secureWs)) {
|
||||
if (packetId == ServerboundPackets1_5_2.PLUGIN_MESSAGE.getId() && Types1_6_4.STRING.read(data).startsWith("EAG|")) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (this.version.isNewerThanOrEqualTo(VersionEnum.r1_7_2tor1_7_5)) {
|
||||
} else if (this.version.isNewerThanOrEqualTo(VersionEnum.r1_7_2tor1_7_5) && !ctx.channel().hasAttr(Main.secureWs)) {
|
||||
final int packetId = PacketTypes.readVarInt(data);
|
||||
if (packetId == this.pluginMessageId && PacketTypes.readString(data, 32767).startsWith("EAG|")) {
|
||||
break;
|
||||
|
@ -295,8 +311,8 @@ public class EaglercraftHandler extends MessageToMessageCodec<WebSocketFrame, By
|
|||
}
|
||||
this.state = State.STATUS;
|
||||
this.version = VersionEnum.r1_8;
|
||||
if (ctx.pipeline().get("legacy-passthrough-handler") != null) {
|
||||
ctx.pipeline().remove("legacy-passthrough-handler");
|
||||
if (ctx.pipeline().get(Client2ProxyChannelInitializer.LEGACY_PASSTHROUGH_INITIAL_HANDLER_NAME) != null) {
|
||||
ctx.pipeline().remove(Client2ProxyChannelInitializer.LEGACY_PASSTHROUGH_INITIAL_HANDLER_NAME);
|
||||
}
|
||||
out.add(this.writeHandshake(ctx.alloc().buffer(), ConnectionState.STATUS));
|
||||
final ByteBuf statusRequest = ctx.alloc().buffer();
|
||||
|
@ -312,7 +328,7 @@ public class EaglercraftHandler extends MessageToMessageCodec<WebSocketFrame, By
|
|||
ctx.close();
|
||||
return;
|
||||
}
|
||||
this.host = HostAndPort.fromString(handshake.requestHeaders().get("Host")).withDefaultPort(80);
|
||||
this.host = HostAndPort.fromString(handshake.requestHeaders().get("Host").replaceAll("__", ".")).withDefaultPort(80);
|
||||
}
|
||||
super.userEventTriggered(ctx, evt);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
package me.ayunami2000.ayunViaProxyEagUtils;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandler;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import io.netty.handler.codec.http.HttpObjectAggregator;
|
||||
import io.netty.handler.codec.http.HttpServerCodec;
|
||||
|
@ -9,14 +12,26 @@ 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.netminecraft.constants.MCPipeline;
|
||||
import net.raphimc.viaproxy.plugins.PluginManager;
|
||||
import net.raphimc.viaproxy.plugins.events.Client2ProxyHandlerCreationEvent;
|
||||
import net.raphimc.viaproxy.proxy.client2proxy.Client2ProxyChannelInitializer;
|
||||
import net.raphimc.viaproxy.proxy.client2proxy.passthrough.PassthroughClient2ProxyChannelInitializer;
|
||||
import net.raphimc.viaproxy.proxy.client2proxy.passthrough.PassthroughClient2ProxyHandler;
|
||||
import net.raphimc.viaproxy.proxy.client2proxy.passthrough.PassthroughInitialHandler;
|
||||
import net.raphimc.viaproxy.proxy.util.ExceptionUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class EaglercraftInitialHandler extends ByteToMessageDecoder {
|
||||
private static SslContext sslContext;
|
||||
private static final Method initChannelMethod;
|
||||
public static SslContext sslContext;
|
||||
|
||||
@Override
|
||||
protected void decode(final ChannelHandlerContext ctx, final ByteBuf in, final List<Object> out) {
|
||||
|
@ -27,7 +42,7 @@ public class EaglercraftInitialHandler extends ByteToMessageDecoder {
|
|||
return;
|
||||
}
|
||||
if (in.readableBytes() >= 3 || in.getByte(0) != 71) {
|
||||
if (in.readableBytes() >= 3 && in.getCharSequence(0, 3, StandardCharsets.UTF_8).equals("GET")) {
|
||||
if ((in.readableBytes() >= 3 && in.getCharSequence(0, 3, StandardCharsets.UTF_8).equals("GET")) || (in.readableBytes() >= 4 && in.getCharSequence(0, 4, StandardCharsets.UTF_8).equals("POST"))) {
|
||||
if (EaglercraftInitialHandler.sslContext != null) {
|
||||
ctx.pipeline().addBefore("eaglercraft-initial-handler", "ws-ssl-handler", EaglercraftInitialHandler.sslContext.newHandler(ctx.alloc()));
|
||||
}
|
||||
|
@ -37,6 +52,43 @@ public class EaglercraftInitialHandler extends ByteToMessageDecoder {
|
|||
ctx.pipeline().addBefore("eaglercraft-initial-handler", "ws-handler", new WebSocketServerProtocolHandler("/", null, true));
|
||||
ctx.pipeline().addBefore("eaglercraft-initial-handler", "ws-active-notifier", new WebSocketActiveNotifier());
|
||||
ctx.pipeline().addBefore("eaglercraft-initial-handler", "eaglercraft-handler", new EaglercraftHandler());
|
||||
ctx.pipeline().replace(Client2ProxyChannelInitializer.LEGACY_PASSTHROUGH_INITIAL_HANDLER_NAME, Client2ProxyChannelInitializer.LEGACY_PASSTHROUGH_INITIAL_HANDLER_NAME, new PassthroughInitialHandler() {
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) {
|
||||
if (ctx.channel().isOpen()) {
|
||||
if (msg.isReadable()) {
|
||||
int lengthOrPacketId = msg.getUnsignedByte(0);
|
||||
if (lengthOrPacketId == 0 || lengthOrPacketId == 1 || lengthOrPacketId == 2 || lengthOrPacketId == 254) {
|
||||
boolean fard = false;
|
||||
for (Map.Entry<String, ChannelHandler> entry : ctx.pipeline()) {
|
||||
if (entry.getKey().equals(Client2ProxyChannelInitializer.LEGACY_PASSTHROUGH_INITIAL_HANDLER_NAME)) {
|
||||
fard = true;
|
||||
}
|
||||
if (fard) {
|
||||
ctx.pipeline().remove(entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
Supplier<ChannelHandler> handlerSupplier = () -> PluginManager.EVENT_MANAGER.call(new Client2ProxyHandlerCreationEvent(new PassthroughClient2ProxyHandler(), true)).getHandler();
|
||||
PassthroughClient2ProxyChannelInitializer channelInitializer = new PassthroughClient2ProxyChannelInitializer(handlerSupplier);
|
||||
try {
|
||||
initChannelMethod.invoke(channelInitializer, ctx.channel());
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
try {
|
||||
((ChannelInboundHandler) ctx.pipeline().get(MCPipeline.HANDLER_HANDLER_NAME)).channelRead(ctx, msg.retain());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
ctx.pipeline().remove(this);
|
||||
ctx.pipeline().fireChannelRead(msg.retain());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
ctx.fireUserEventTriggered(EaglercraftClientConnected.INSTANCE);
|
||||
ctx.pipeline().fireChannelRead(in.readBytes(in.readableBytes()));
|
||||
} else {
|
||||
|
@ -55,14 +107,16 @@ public class EaglercraftInitialHandler extends ByteToMessageDecoder {
|
|||
throw new RuntimeException("Failed to load SSL context", e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
initChannelMethod = PassthroughClient2ProxyChannelInitializer.class.getDeclaredMethod("initChannel", Channel.class);
|
||||
initChannelMethod.setAccessible(true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class EaglercraftClientConnected {
|
||||
public static final EaglercraftClientConnected INSTANCE;
|
||||
|
||||
static {
|
||||
INSTANCE = new EaglercraftClientConnected();
|
||||
}
|
||||
public static final EaglercraftClientConnected INSTANCE = new EaglercraftClientConnected();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -9,7 +9,10 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
public class FunnyConfig extends Config {
|
||||
private boolean premiumSkins = false;
|
||||
public static boolean premiumSkins = false;
|
||||
public static boolean eaglerUtils = true;
|
||||
public static boolean eaglerSkins = true;
|
||||
public static boolean eaglerVoice = true;
|
||||
|
||||
protected FunnyConfig(File configFile) {
|
||||
super(configFile);
|
||||
|
@ -17,14 +20,26 @@ public class FunnyConfig extends Config {
|
|||
|
||||
@Override
|
||||
public URL getDefaultConfigURL() {
|
||||
return Main.class.getResource("/eaglerskins.yml");
|
||||
return Main.class.getResource("/vpeagutils.yml");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleConfig(Map<String, Object> map) {
|
||||
Object item = map.get("premium-skins");
|
||||
if (item instanceof Boolean) {
|
||||
this.premiumSkins = (Boolean) item;
|
||||
premiumSkins = (Boolean) item;
|
||||
}
|
||||
item = map.get("eagler-utils");
|
||||
if (item instanceof Boolean) {
|
||||
eaglerUtils = (Boolean) item;
|
||||
}
|
||||
item = map.get("eagler-skins");
|
||||
if (item instanceof Boolean) {
|
||||
eaglerSkins = (Boolean) item;
|
||||
}
|
||||
item = map.get("eagler-voice");
|
||||
if (item instanceof Boolean) {
|
||||
eaglerVoice = (Boolean) item;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,8 +47,4 @@ public class FunnyConfig extends Config {
|
|||
public List<String> getUnsupportedOptions() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public boolean getPremiumSkins() {
|
||||
return this.premiumSkins;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
package me.ayunami2000.ayunViaProxyEagUtils;
|
||||
|
||||
/**
|
||||
* base implementation of MD4 family style digest as outlined in "Handbook of
|
||||
* Applied Cryptography", pages 344 - 347.
|
||||
*/
|
||||
public abstract class GeneralDigest {
|
||||
private byte[] xBuf;
|
||||
private int xBufOff;
|
||||
|
||||
private long byteCount;
|
||||
|
||||
/**
|
||||
* Standard constructor
|
||||
*/
|
||||
protected GeneralDigest() {
|
||||
xBuf = new byte[4];
|
||||
xBufOff = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor. We are using copy constructors in place of the
|
||||
* Object.clone() interface as this interface is not supported by J2ME.
|
||||
*/
|
||||
protected GeneralDigest(GeneralDigest t) {
|
||||
xBuf = new byte[t.xBuf.length];
|
||||
System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length);
|
||||
|
||||
xBufOff = t.xBufOff;
|
||||
byteCount = t.byteCount;
|
||||
}
|
||||
|
||||
public void update(byte in) {
|
||||
xBuf[xBufOff++] = in;
|
||||
|
||||
if (xBufOff == xBuf.length) {
|
||||
processWord(xBuf, 0);
|
||||
xBufOff = 0;
|
||||
}
|
||||
|
||||
byteCount++;
|
||||
}
|
||||
|
||||
public void update(byte[] in, int inOff, int len) {
|
||||
//
|
||||
// fill the current word
|
||||
//
|
||||
while ((xBufOff != 0) && (len > 0)) {
|
||||
update(in[inOff]);
|
||||
|
||||
inOff++;
|
||||
len--;
|
||||
}
|
||||
|
||||
//
|
||||
// process whole words.
|
||||
//
|
||||
while (len > xBuf.length) {
|
||||
processWord(in, inOff);
|
||||
|
||||
inOff += xBuf.length;
|
||||
len -= xBuf.length;
|
||||
byteCount += xBuf.length;
|
||||
}
|
||||
|
||||
//
|
||||
// load in the remainder.
|
||||
//
|
||||
while (len > 0) {
|
||||
update(in[inOff]);
|
||||
|
||||
inOff++;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
public void finish() {
|
||||
long bitLength = (byteCount << 3);
|
||||
|
||||
//
|
||||
// add the pad bytes.
|
||||
//
|
||||
update((byte) 128);
|
||||
|
||||
while (xBufOff != 0) {
|
||||
update((byte) 0);
|
||||
}
|
||||
|
||||
processLength(bitLength);
|
||||
|
||||
processBlock();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
byteCount = 0;
|
||||
|
||||
xBufOff = 0;
|
||||
for (int i = 0; i < xBuf.length; i++) {
|
||||
xBuf[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void processWord(byte[] in, int inOff);
|
||||
|
||||
protected abstract void processLength(long bitLength);
|
||||
|
||||
protected abstract void processBlock();
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package me.ayunami2000.ayunViaProxyEagUtils;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2022-2023 LAX1DUDE. All Rights Reserved.
|
||||
*
|
||||
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
|
||||
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
|
||||
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
|
||||
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
|
||||
*
|
||||
* NOT FOR COMMERCIAL OR MALICIOUS USE
|
||||
*
|
||||
* (please read the 'LICENSE' file this repo's root directory for more info)
|
||||
*
|
||||
*/
|
||||
public class HandshakePacketTypes {
|
||||
|
||||
public static final String AUTHENTICATION_REQUIRED = "Authentication Required:";
|
||||
|
||||
public static final int PROTOCOL_CLIENT_VERSION = 0x01;
|
||||
public static final int PROTOCOL_SERVER_VERSION = 0x02;
|
||||
public static final int PROTOCOL_VERSION_MISMATCH = 0x03;
|
||||
public static final int PROTOCOL_CLIENT_REQUEST_LOGIN = 0x04;
|
||||
public static final int PROTOCOL_SERVER_ALLOW_LOGIN = 0x05;
|
||||
public static final int PROTOCOL_SERVER_DENY_LOGIN = 0x06;
|
||||
public static final int PROTOCOL_CLIENT_PROFILE_DATA = 0x07;
|
||||
public static final int PROTOCOL_CLIENT_FINISH_LOGIN = 0x08;
|
||||
public static final int PROTOCOL_SERVER_FINISH_LOGIN = 0x09;
|
||||
public static final int PROTOCOL_SERVER_ERROR = 0xFF;
|
||||
|
||||
public static final int STATE_OPENED = 0x00;
|
||||
public static final int STATE_CLIENT_VERSION = 0x01;
|
||||
public static final int STATE_CLIENT_LOGIN = 0x02;
|
||||
public static final int STATE_CLIENT_COMPLETE = 0x03;
|
||||
|
||||
public static final int SERVER_ERROR_UNKNOWN_PACKET = 0x01;
|
||||
public static final int SERVER_ERROR_INVALID_PACKET = 0x02;
|
||||
public static final int SERVER_ERROR_WRONG_PACKET = 0x03;
|
||||
public static final int SERVER_ERROR_EXCESSIVE_PROFILE_DATA = 0x04;
|
||||
public static final int SERVER_ERROR_DUPLICATE_PROFILE_DATA = 0x05;
|
||||
public static final int SERVER_ERROR_RATELIMIT_BLOCKED = 0x06;
|
||||
public static final int SERVER_ERROR_RATELIMIT_LOCKED = 0x07;
|
||||
public static final int SERVER_ERROR_CUSTOM_MESSAGE = 0x08;
|
||||
public static final int SERVER_ERROR_AUTHENTICATION_REQUIRED = 0x09;
|
||||
|
||||
public static final int AUTH_METHOD_NONE = 0x0;
|
||||
public static final int AUTH_METHOD_EAGLER_SHA256 = 0x01;
|
||||
public static final int AUTH_METHOD_AUTHME_SHA256 = 0x02;
|
||||
public static final int AUTH_METHOD_PLAINTEXT = 0xFF;
|
||||
|
||||
public static final byte[] EAGLER_SHA256_SALT_BASE = new byte[] { (byte) 117, (byte) 43, (byte) 1, (byte) 112,
|
||||
(byte) 75, (byte) 3, (byte) 188, (byte) 61, (byte) 121, (byte) 31, (byte) 34, (byte) 181, (byte) 234,
|
||||
(byte) 31, (byte) 247, (byte) 72, (byte) 12, (byte) 168, (byte) 138, (byte) 45, (byte) 143, (byte) 77,
|
||||
(byte) 118, (byte) 245, (byte) 187, (byte) 242, (byte) 188, (byte) 219, (byte) 160, (byte) 235, (byte) 235,
|
||||
(byte) 68 };
|
||||
|
||||
public static final byte[] EAGLER_SHA256_SALT_SAVE = new byte[] { (byte) 49, (byte) 25, (byte) 39, (byte) 38,
|
||||
(byte) 253, (byte) 85, (byte) 70, (byte) 245, (byte) 71, (byte) 150, (byte) 253, (byte) 206, (byte) 4,
|
||||
(byte) 26, (byte) 198, (byte) 249, (byte) 145, (byte) 251, (byte) 232, (byte) 174, (byte) 186, (byte) 98,
|
||||
(byte) 27, (byte) 232, (byte) 55, (byte) 144, (byte) 83, (byte) 21, (byte) 36, (byte) 55, (byte) 170,
|
||||
(byte) 118 };
|
||||
|
||||
}
|
|
@ -1,28 +1,149 @@
|
|||
package me.ayunami2000.ayunViaProxyEagUtils;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.handler.codec.http.*;
|
||||
import io.netty.handler.codec.http.websocketx.*;
|
||||
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketClientCompressionHandler;
|
||||
import io.netty.handler.ssl.SslHandler;
|
||||
import io.netty.util.AttributeKey;
|
||||
import net.lenni0451.lambdaevents.EventHandler;
|
||||
import net.raphimc.netminecraft.constants.MCPipeline;
|
||||
import net.raphimc.netminecraft.netty.connection.NetClient;
|
||||
import net.raphimc.netminecraft.util.ServerAddress;
|
||||
import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.types.Types1_6_4;
|
||||
import net.raphimc.vialoader.util.VersionEnum;
|
||||
import net.raphimc.viaproxy.plugins.PluginManager;
|
||||
import net.raphimc.viaproxy.plugins.ViaProxyPlugin;
|
||||
import net.raphimc.viaproxy.plugins.events.Client2ProxyChannelInitializeEvent;
|
||||
import net.raphimc.viaproxy.plugins.events.Proxy2ServerChannelInitializeEvent;
|
||||
import net.raphimc.viaproxy.plugins.events.types.ITyped;
|
||||
import net.raphimc.viaproxy.proxy.session.LegacyProxyConnection;
|
||||
import net.raphimc.viaproxy.proxy.session.ProxyConnection;
|
||||
import net.raphimc.viaproxy.proxy.util.ExceptionUtil;
|
||||
|
||||
import javax.net.ssl.*;
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
public class Main extends ViaProxyPlugin {
|
||||
public static final AttributeKey<Boolean> secureWs = AttributeKey.newInstance("eag-secure-ws");
|
||||
public static final AttributeKey<String> wsPath = AttributeKey.newInstance("eag-ws-path");
|
||||
public static final AttributeKey<String> eagxPass = AttributeKey.newInstance("eag-x-pass");
|
||||
private static final SSLContext sc;
|
||||
|
||||
static {
|
||||
try {
|
||||
TrustManager[] trustAllCerts = new TrustManager[]{
|
||||
new X509TrustManager() {
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return new X509Certificate[0];
|
||||
}
|
||||
|
||||
public void checkClientTrusted(X509Certificate[] certs, String authType) {
|
||||
}
|
||||
|
||||
public void checkServerTrusted(X509Certificate[] certs, String authType) {
|
||||
}
|
||||
}};
|
||||
|
||||
// Ignore differences between given hostname and certificate hostname
|
||||
sc = SSLContext.getInstance("SSL");
|
||||
sc.init(null, trustAllCerts, new SecureRandom());
|
||||
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
|
||||
HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
|
||||
} catch (KeyManagementException | NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void onEnable() {
|
||||
PluginManager.EVENT_MANAGER.register(this);
|
||||
(new FunnyConfig(new File("ViaLoader", "vpeagutils.yml"))).reloadConfig();
|
||||
EaglerXSkinHandler.skinService = new SkinService();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onEvent(final Proxy2ServerChannelInitializeEvent event) throws URISyntaxException {
|
||||
if (event.getType() == ITyped.Type.POST) {
|
||||
Channel ch = event.getChannel();
|
||||
|
||||
NetClient proxyConnection;
|
||||
Channel c2p;
|
||||
ServerAddress addr;
|
||||
if (event.isLegacyPassthrough()) {
|
||||
proxyConnection = LegacyProxyConnection.fromChannel(ch);
|
||||
c2p = ((LegacyProxyConnection) proxyConnection).getC2P();
|
||||
addr = ((LegacyProxyConnection) proxyConnection).getServerAddress();
|
||||
} else {
|
||||
proxyConnection = ProxyConnection.fromChannel(ch);
|
||||
c2p = ((ProxyConnection) proxyConnection).getC2P();
|
||||
addr = ((ProxyConnection) proxyConnection).getServerAddress();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
c2p.attr(secureWs).set(true);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (c2p.hasAttr(secureWs)) {
|
||||
ch.attr(MCPipeline.COMPRESSION_THRESHOLD_ATTRIBUTE_KEY).set(-2);
|
||||
if (proxyConnection instanceof ProxyConnection && ((ProxyConnection) proxyConnection).getServerVersion().isNewerThan(VersionEnum.r1_6_4)) {
|
||||
ch.pipeline().remove(MCPipeline.SIZER_HANDLER_NAME);
|
||||
} else if (ch.pipeline().get(MCPipeline.ENCRYPTION_HANDLER_NAME) != null) {
|
||||
ch.pipeline().remove(MCPipeline.ENCRYPTION_HANDLER_NAME);
|
||||
}
|
||||
StringBuilder url = new StringBuilder("ws");
|
||||
boolean secure = c2p.attr(secureWs).get();
|
||||
if (secure) {
|
||||
final SSLEngine sslEngine = sc.createSSLEngine(addr.getAddress(), addr.getPort());
|
||||
sslEngine.setUseClientMode(true);
|
||||
sslEngine.setNeedClientAuth(false);
|
||||
ch.pipeline().addFirst("eag-server-ssl", new SslHandler(sslEngine));
|
||||
url.append("s");
|
||||
ch.pipeline().addAfter("eag-server-ssl", "eag-server-http-codec", new HttpClientCodec());
|
||||
} else {
|
||||
ch.pipeline().addFirst("eag-server-http-codec", new HttpClientCodec());
|
||||
}
|
||||
url.append("://").append(addr.getAddress());
|
||||
boolean addPort = (secure && addr.getPort() != 443) || (!secure && addr.getPort() != 80);
|
||||
if (addPort) {
|
||||
url.append(":").append(addr.getPort());
|
||||
}
|
||||
String path = c2p.attr(wsPath).get();
|
||||
if (path != null) {
|
||||
url.append("/").append(path);
|
||||
}
|
||||
URI uri = new URI(url.toString());
|
||||
HttpHeaders headers = new DefaultHttpHeaders();
|
||||
headers.set(HttpHeaderNames.HOST, uri.getHost() + (addPort ? ":" + uri.getPort() : ""));
|
||||
headers.set(HttpHeaderNames.ORIGIN, "via.shhnowisnottheti.me");
|
||||
ch.pipeline().addAfter("eag-server-http-codec", "eag-server-http-aggregator", new HttpObjectAggregator(2097152, true));
|
||||
ch.pipeline().addAfter("eag-server-http-aggregator", "eag-server-ws-compression", WebSocketClientCompressionHandler.INSTANCE);
|
||||
ch.pipeline().addAfter("eag-server-ws-compression", "eag-server-ws-handshaker", new WebSocketClientProtocolHandler(WebSocketClientHandshakerFactory.newHandshaker(uri, WebSocketVersion.V13, null, true, headers, 2097152)));
|
||||
ch.pipeline().addAfter("eag-server-ws-handshaker", "eag-server-ws-ready", new WebSocketConnectedNotifier());
|
||||
ch.pipeline().addAfter("eag-server-ws-ready", "eag-server-handler", new EaglerServerHandler(proxyConnection, c2p.attr(eagxPass).get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onEvent(final Client2ProxyChannelInitializeEvent event) {
|
||||
if (event.isLegacyPassthrough()) return;
|
||||
if (event.getType() == ITyped.Type.PRE) {
|
||||
event.getChannel().pipeline().addLast("eaglercraft-initial-handler", new EaglercraftInitialHandler());
|
||||
}
|
||||
if (event.getType() == ITyped.Type.POST) {
|
||||
if (event.getType() == ITyped.Type.POST && FunnyConfig.eaglerUtils) {
|
||||
event.getChannel().pipeline().addAfter("eaglercraft-initial-handler", "ayun-eag-detector", new EaglerConnectionHandler());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package me.ayunami2000.ayunViaProxyEagUtils;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
|
||||
public class MsgPromise {
|
||||
public Object msg;
|
||||
public ChannelPromise promise;
|
||||
public MsgPromise(Object msg, ChannelPromise promise) {
|
||||
this.msg = msg;
|
||||
this.promise = promise;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,233 @@
|
|||
package me.ayunami2000.ayunViaProxyEagUtils;
|
||||
|
||||
public class SHA256Digest extends GeneralDigest {
|
||||
|
||||
private static final int DIGEST_LENGTH = 32;
|
||||
|
||||
private int H1, H2, H3, H4, H5, H6, H7, H8;
|
||||
|
||||
private int[] X = new int[64];
|
||||
private int xOff;
|
||||
|
||||
public SHA256Digest() {
|
||||
reset();
|
||||
}
|
||||
|
||||
public static int bigEndianToInt(byte[] bs, int off) {
|
||||
int n = bs[off] << 24;
|
||||
n |= (bs[++off] & 0xff) << 16;
|
||||
n |= (bs[++off] & 0xff) << 8;
|
||||
n |= (bs[++off] & 0xff);
|
||||
return n;
|
||||
}
|
||||
|
||||
public static void bigEndianToInt(byte[] bs, int off, int[] ns) {
|
||||
for (int i = 0; i < ns.length; ++i) {
|
||||
ns[i] = bigEndianToInt(bs, off);
|
||||
off += 4;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] intToBigEndian(int n) {
|
||||
byte[] bs = new byte[4];
|
||||
intToBigEndian(n, bs, 0);
|
||||
return bs;
|
||||
}
|
||||
|
||||
public static void intToBigEndian(int n, byte[] bs, int off) {
|
||||
bs[off] = (byte) (n >>> 24);
|
||||
bs[++off] = (byte) (n >>> 16);
|
||||
bs[++off] = (byte) (n >>> 8);
|
||||
bs[++off] = (byte) (n);
|
||||
}
|
||||
|
||||
protected void processWord(byte[] in, int inOff) {
|
||||
X[xOff] = bigEndianToInt(in, inOff);
|
||||
|
||||
if (++xOff == 16) {
|
||||
processBlock();
|
||||
}
|
||||
}
|
||||
|
||||
protected void processLength(long bitLength) {
|
||||
if (xOff > 14) {
|
||||
processBlock();
|
||||
}
|
||||
|
||||
X[14] = (int) (bitLength >>> 32);
|
||||
X[15] = (int) (bitLength & 0xffffffff);
|
||||
}
|
||||
|
||||
public int doFinal(byte[] out, int outOff) {
|
||||
finish();
|
||||
|
||||
intToBigEndian(H1, out, outOff);
|
||||
intToBigEndian(H2, out, outOff + 4);
|
||||
intToBigEndian(H3, out, outOff + 8);
|
||||
intToBigEndian(H4, out, outOff + 12);
|
||||
intToBigEndian(H5, out, outOff + 16);
|
||||
intToBigEndian(H6, out, outOff + 20);
|
||||
intToBigEndian(H7, out, outOff + 24);
|
||||
intToBigEndian(H8, out, outOff + 28);
|
||||
|
||||
reset();
|
||||
|
||||
return DIGEST_LENGTH;
|
||||
}
|
||||
|
||||
/**
|
||||
* reset the chaining variables
|
||||
*/
|
||||
public void reset() {
|
||||
super.reset();
|
||||
|
||||
/*
|
||||
* SHA-256 initial hash value The first 32 bits of the fractional parts of the
|
||||
* square roots of the first eight prime numbers
|
||||
*/
|
||||
|
||||
H1 = 0x6a09e667;
|
||||
H2 = 0xbb67ae85;
|
||||
H3 = 0x3c6ef372;
|
||||
H4 = 0xa54ff53a;
|
||||
H5 = 0x510e527f;
|
||||
H6 = 0x9b05688c;
|
||||
H7 = 0x1f83d9ab;
|
||||
H8 = 0x5be0cd19;
|
||||
|
||||
xOff = 0;
|
||||
for (int i = 0; i != X.length; i++) {
|
||||
X[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected void processBlock() {
|
||||
//
|
||||
// expand 16 word block into 64 word blocks.
|
||||
//
|
||||
for (int t = 16; t <= 63; t++) {
|
||||
X[t] = Theta1(X[t - 2]) + X[t - 7] + Theta0(X[t - 15]) + X[t - 16];
|
||||
}
|
||||
|
||||
//
|
||||
// set up working variables.
|
||||
//
|
||||
int a = H1;
|
||||
int b = H2;
|
||||
int c = H3;
|
||||
int d = H4;
|
||||
int e = H5;
|
||||
int f = H6;
|
||||
int g = H7;
|
||||
int h = H8;
|
||||
|
||||
int t = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
// t = 8 * i
|
||||
h += Sum1(e) + Ch(e, f, g) + K[t] + X[t];
|
||||
d += h;
|
||||
h += Sum0(a) + Maj(a, b, c);
|
||||
++t;
|
||||
|
||||
// t = 8 * i + 1
|
||||
g += Sum1(d) + Ch(d, e, f) + K[t] + X[t];
|
||||
c += g;
|
||||
g += Sum0(h) + Maj(h, a, b);
|
||||
++t;
|
||||
|
||||
// t = 8 * i + 2
|
||||
f += Sum1(c) + Ch(c, d, e) + K[t] + X[t];
|
||||
b += f;
|
||||
f += Sum0(g) + Maj(g, h, a);
|
||||
++t;
|
||||
|
||||
// t = 8 * i + 3
|
||||
e += Sum1(b) + Ch(b, c, d) + K[t] + X[t];
|
||||
a += e;
|
||||
e += Sum0(f) + Maj(f, g, h);
|
||||
++t;
|
||||
|
||||
// t = 8 * i + 4
|
||||
d += Sum1(a) + Ch(a, b, c) + K[t] + X[t];
|
||||
h += d;
|
||||
d += Sum0(e) + Maj(e, f, g);
|
||||
++t;
|
||||
|
||||
// t = 8 * i + 5
|
||||
c += Sum1(h) + Ch(h, a, b) + K[t] + X[t];
|
||||
g += c;
|
||||
c += Sum0(d) + Maj(d, e, f);
|
||||
++t;
|
||||
|
||||
// t = 8 * i + 6
|
||||
b += Sum1(g) + Ch(g, h, a) + K[t] + X[t];
|
||||
f += b;
|
||||
b += Sum0(c) + Maj(c, d, e);
|
||||
++t;
|
||||
|
||||
// t = 8 * i + 7
|
||||
a += Sum1(f) + Ch(f, g, h) + K[t] + X[t];
|
||||
e += a;
|
||||
a += Sum0(b) + Maj(b, c, d);
|
||||
++t;
|
||||
}
|
||||
|
||||
H1 += a;
|
||||
H2 += b;
|
||||
H3 += c;
|
||||
H4 += d;
|
||||
H5 += e;
|
||||
H6 += f;
|
||||
H7 += g;
|
||||
H8 += h;
|
||||
|
||||
//
|
||||
// reset the offset and clean out the word buffer.
|
||||
//
|
||||
xOff = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
X[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* SHA-256 functions */
|
||||
private static int Ch(int x, int y, int z) {
|
||||
return (x & y) ^ ((~x) & z);
|
||||
// return z ^ (x & (y ^ z));
|
||||
}
|
||||
|
||||
private static int Maj(int x, int y, int z) {
|
||||
// return (x & y) ^ (x & z) ^ (y & z);
|
||||
return (x & y) | (z & (x ^ y));
|
||||
}
|
||||
|
||||
private static int Sum0(int x) {
|
||||
return ((x >>> 2) | (x << 30)) ^ ((x >>> 13) | (x << 19)) ^ ((x >>> 22) | (x << 10));
|
||||
}
|
||||
|
||||
private static int Sum1(int x) {
|
||||
return ((x >>> 6) | (x << 26)) ^ ((x >>> 11) | (x << 21)) ^ ((x >>> 25) | (x << 7));
|
||||
}
|
||||
|
||||
private static int Theta0(int x) {
|
||||
return ((x >>> 7) | (x << 25)) ^ ((x >>> 18) | (x << 14)) ^ (x >>> 3);
|
||||
}
|
||||
|
||||
private static int Theta1(int x) {
|
||||
return ((x >>> 17) | (x << 15)) ^ ((x >>> 19) | (x << 13)) ^ (x >>> 10);
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA-256 Constants (represent the first 32 bits of the fractional parts of the
|
||||
* cube roots of the first sixty-four prime numbers)
|
||||
*/
|
||||
static final int K[] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4,
|
||||
0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152,
|
||||
0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138,
|
||||
0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70,
|
||||
0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
|
||||
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa,
|
||||
0xa4506ceb, 0xbef9a3f7, 0xc67178f2 };
|
||||
|
||||
}
|
|
@ -21,7 +21,7 @@ public class SkinPackets {
|
|||
break;
|
||||
}
|
||||
case 6: {
|
||||
if (EaglerXSkinHandler.skinService.loadPremiumSkins) {
|
||||
if (FunnyConfig.premiumSkins) {
|
||||
processGetOtherSkinByURL(data, sender, skinService);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -6,15 +6,9 @@ import io.netty.channel.ChannelHandlerContext;
|
|||
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
|
||||
import net.raphimc.netminecraft.constants.MCPackets;
|
||||
import net.raphimc.netminecraft.packet.PacketTypes;
|
||||
import net.raphimc.vialegacy.ViaLegacy;
|
||||
import net.raphimc.vialegacy.ViaLegacyConfig;
|
||||
import net.raphimc.vialoader.util.VersionEnum;
|
||||
import net.raphimc.viaproxy.ViaProxy;
|
||||
import net.raphimc.viaproxy.cli.options.Options;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.DataBufferByte;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
|
@ -23,15 +17,10 @@ import java.util.UUID;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class SkinService {
|
||||
public final boolean loadPremiumSkins;
|
||||
private final ConcurrentHashMap<UUID, CachedSkin> skinCache;
|
||||
|
||||
public SkinService() {
|
||||
this.skinCache = new ConcurrentHashMap<>();
|
||||
File funnyFile = new File("ViaLoader", "eaglerskins.yml");
|
||||
FunnyConfig funnyConfig = new FunnyConfig(funnyFile);
|
||||
funnyConfig.reloadConfig();
|
||||
this.loadPremiumSkins = funnyConfig.getPremiumSkins();
|
||||
}
|
||||
|
||||
private static void sendData(final ChannelHandlerContext ctx, final byte[] data) {
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
package me.ayunami2000.ayunViaProxyEagUtils;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelDuplexHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
|
||||
import io.netty.handler.codec.http.websocketx.WebSocketClientProtocolHandler;
|
||||
import io.netty.handler.ssl.SslCompletionEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class WebSocketConnectedNotifier extends ChannelDuplexHandler {
|
||||
private final List<Object> msgsRead = new ArrayList<>();
|
||||
private final List<MsgPromise> msgsWrite = new ArrayList<>();
|
||||
@Override
|
||||
public void userEventTriggered(final ChannelHandlerContext ctx, final Object evt) {
|
||||
if (evt == WebSocketClientProtocolHandler.ClientHandshakeStateEvent.HANDSHAKE_COMPLETE) {
|
||||
ctx.fireChannelActive();
|
||||
ctx.fireUserEventTriggered(evt);
|
||||
ctx.pipeline().remove(this);
|
||||
for (final Object msg : msgsRead)
|
||||
ctx.fireChannelRead(msg);
|
||||
msgsRead.clear();
|
||||
for (final MsgPromise msg : msgsWrite)
|
||||
ctx.write(msg.msg, msg.promise);
|
||||
ctx.flush();
|
||||
msgsWrite.clear();
|
||||
} else if (evt == WebSocketClientProtocolHandler.ClientHandshakeStateEvent.HANDSHAKE_TIMEOUT) {
|
||||
ctx.fireUserEventTriggered(evt);
|
||||
ctx.close();
|
||||
} else {
|
||||
if (evt instanceof SslCompletionEvent && !((SslCompletionEvent) evt).isSuccess()) {
|
||||
((SslCompletionEvent) evt).cause().printStackTrace();
|
||||
}
|
||||
ctx.fireUserEventTriggered(evt);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void channelActive(final ChannelHandlerContext ctx) {
|
||||
//
|
||||
}
|
||||
@Override
|
||||
public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
|
||||
if (msg instanceof ByteBuf) {
|
||||
msgsRead.add(msg);
|
||||
} else {
|
||||
ctx.fireChannelRead(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||
if (msg instanceof BinaryWebSocketFrame || msg instanceof ByteBuf) {
|
||||
msgsWrite.add(new MsgPromise(msg, promise));
|
||||
} else {
|
||||
ctx.write(msg, promise);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
# Use premium skins
|
||||
premium-skins: false
|
8
src/main/resources/vpeagutils.yml
Normal file
8
src/main/resources/vpeagutils.yml
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Use premium skins
|
||||
premium-skins: false
|
||||
# Handle Eagler skins and voice on the proxy side
|
||||
eagler-utils: true
|
||||
# Sync Eagler skins
|
||||
eagler-skins: true
|
||||
# Enable Eagler voice chat
|
||||
eagler-voice: true
|
Loading…
Reference in New Issue
Block a user