forked from BLOCKFANTASY/LOOHP-Limbo
129 lines
4.4 KiB
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;
|
|
}
|
|
}
|
|
}
|