LimboService/src/main/java/com/loohp/limbo/utils/ForwardingUtils.java

129 lines
4.4 KiB
Java

package com.loohp.limbo.utils;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.UUID;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import com.loohp.limbo.Limbo;
public class ForwardingUtils {
public static final NamespacedKey VELOCITY_FORWARDING_CHANNEL = new NamespacedKey("velocity", "player_info");
public static boolean validateVelocityModernResponse(byte[] data) throws IOException {
ByteArrayInputStream byteIn = new ByteArrayInputStream(data);
DataInputStream input = new DataInputStream(byteIn);
byte[] signature = new byte[32];
input.readFully(signature);
boolean foundValid = false;
try {
Mac mac = Mac.getInstance("HmacSHA256");
for (String secret : Limbo.getInstance().getServerProperties().getForwardingSecrets()) {
SecretKey key = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
mac.init(key);
mac.update(data, 32, data.length - 32);
byte[] sig = mac.doFinal();
if (Arrays.equals(signature, sig)) {
foundValid = true;
break;
}
}
} catch (InvalidKeyException e) {
throw new RuntimeException("Unable to authenticate data", e);
} catch (NoSuchAlgorithmException e) {
// Should never happen
throw new AssertionError(e);
}
return foundValid;
}
public static VelocityModernForwardingData getVelocityDataFrom(byte[] data) throws IOException {
ByteArrayInputStream byteIn = new ByteArrayInputStream(data);
DataInputStream input = new DataInputStream(byteIn);
input.skipBytes(32);
int velocityVersion = DataTypeIO.readVarInt(input);
if (velocityVersion != 1) {
System.out.println("Unsupported Velocity version! Stopping Execution");
throw new AssertionError("Unknown Velocity Packet");
}
String address = DataTypeIO.readString(input, StandardCharsets.UTF_8);
UUID uuid = DataTypeIO.readUUID(input);
String username = DataTypeIO.readString(input, StandardCharsets.UTF_8);
//cycle properties
MojangAPIUtils.SkinResponse response = null;
int count = DataTypeIO.readVarInt(input);
for (int i = 0; i < count; ++i) {
String propertyName = DataTypeIO.readString(input, StandardCharsets.UTF_8);
String propertyValue = DataTypeIO.readString(input, StandardCharsets.UTF_8);
String propertySignature = "";
boolean signatureIncluded = input.readBoolean();
if (signatureIncluded) {
propertySignature = DataTypeIO.readString(input, StandardCharsets.UTF_8);
}
if (propertyName.equals("textures")) {
response = new MojangAPIUtils.SkinResponse(propertyValue, propertySignature);
break; // we don't use others properties for now
}
}
return new VelocityModernForwardingData(velocityVersion, address, uuid, username, response);
}
public static class VelocityModernForwardingData {
private final int version;
private final String ipAddress;
private final UUID uuid;
private final String username;
private final MojangAPIUtils.SkinResponse skinResponse;
public VelocityModernForwardingData(int version, String ipAddress, UUID uuid, String username, MojangAPIUtils.SkinResponse skinResponse) {
this.version = version;
this.ipAddress = ipAddress;
this.uuid = uuid;
this.username = username;
this.skinResponse = skinResponse;
}
public int getVersion()
{
return version;
}
public String getIpAddress()
{
return ipAddress;
}
public UUID getUuid()
{
return uuid;
}
public String getUsername()
{
return username;
}
public MojangAPIUtils.SkinResponse getSkinResponse()
{
return skinResponse;
}
}
}