805cebd856
Signed-off-by: Fred Heinecke <fred.heinecke@yahoo.com>
134 lines
4.0 KiB
Go
134 lines
4.0 KiB
Go
package mcproto
|
|
|
|
import (
|
|
"bytes"
|
|
"strings"
|
|
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
const invalidPacketDataBytesMsg = "data should be byte slice from Packet.Data"
|
|
|
|
// DecodeHandshake takes the Packet.Data bytes and decodes a Handshake message from it
|
|
func DecodeHandshake(data interface{}) (*Handshake, error) {
|
|
|
|
dataBytes, ok := data.([]byte)
|
|
if !ok {
|
|
return nil, errors.New(invalidPacketDataBytesMsg)
|
|
}
|
|
|
|
handshake := &Handshake{}
|
|
buffer := bytes.NewBuffer(dataBytes)
|
|
var err error
|
|
|
|
protocolVersion, err := ReadVarInt(buffer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
handshake.ProtocolVersion = ProtocolVersion(protocolVersion)
|
|
|
|
handshake.ServerAddress, err = ReadString(buffer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Forge Mod Loader adds some data after the server address. Truncate it.
|
|
handshake.ServerAddress, _, _ = strings.Cut(handshake.ServerAddress, string(rune(0)))
|
|
|
|
handshake.ServerPort, err = ReadUnsignedShort(buffer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
nextState, err := ReadVarInt(buffer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
handshake.NextState = State(nextState)
|
|
return handshake, nil
|
|
}
|
|
|
|
// DecodeLoginStart takes the Packet.Data bytes and decodes a LoginStart message from it
|
|
func DecodeLoginStart(protocolVersion ProtocolVersion, data interface{}) (*LoginStart, error) {
|
|
dataBytes, ok := data.([]byte)
|
|
if !ok {
|
|
return nil, errors.New(invalidPacketDataBytesMsg)
|
|
}
|
|
|
|
loginStart := NewLoginStart()
|
|
buffer := bytes.NewBuffer(dataBytes)
|
|
var err error
|
|
|
|
loginStart.Name, err = ReadString(buffer)
|
|
if err != nil {
|
|
return loginStart, errors.Wrap(err, "failed to read username")
|
|
}
|
|
|
|
// These versions can send player keypair data. Ignore it.
|
|
// References:
|
|
// * https://github.com/MCCTeam/Minecraft-Console-Client/blob/f785f509f228bf787c237ac139e6f666a960819a/MinecraftClient/Protocol/Handlers/Protocol18.cs#L2808-L2828
|
|
// * https://minecraft.wiki/w/Minecraft_Wiki:Projects/wiki.vg_merge/Protocol?oldid=2772902#Login_Start
|
|
if protocolVersion >= ProtocolVersion1_19 && protocolVersion <= ProtocolVersion1_19_2 {
|
|
hasSignatureData, err := ReadBoolean(buffer)
|
|
if err != nil {
|
|
return loginStart, errors.Wrap(err, "failed to read has signature data flag")
|
|
}
|
|
|
|
if hasSignatureData {
|
|
// Read and discard the data
|
|
_, err = ReadLong(buffer) // Expiration time
|
|
if err != nil {
|
|
return loginStart, errors.Wrap(err, "failed to read expiration time")
|
|
}
|
|
|
|
pubKeyLength, err := ReadVarInt(buffer) // Length of the public key
|
|
if err != nil {
|
|
return loginStart, errors.Wrap(err, "failed to read public key length")
|
|
}
|
|
|
|
_, err = ReadByteArray(buffer, pubKeyLength) // Public key data
|
|
if err != nil {
|
|
return loginStart, errors.Wrap(err, "failed to read public key")
|
|
}
|
|
|
|
signatureLength, err := ReadVarInt(buffer) // Length of the signature
|
|
if err != nil {
|
|
return loginStart, errors.Wrap(err, "failed to read signature length")
|
|
}
|
|
|
|
_, err = ReadByteArray(buffer, signatureLength) // Signature data
|
|
if err != nil {
|
|
return loginStart, errors.Wrap(err, "failed to read signature")
|
|
}
|
|
}
|
|
}
|
|
|
|
// References:
|
|
// * https://github.com/MCCTeam/Minecraft-Console-Client/blob/f785f509f228bf787c237ac139e6f666a960819a/MinecraftClient/Protocol/Handlers/Protocol18.cs#L2831-L2853
|
|
// * https://minecraft.wiki/w/Minecraft_Wiki:Projects/wiki.vg_merge/Protocol?oldid=2772944#Login_Start
|
|
switch {
|
|
case protocolVersion >= ProtocolVersion1_19_2 && protocolVersion < ProtocolVersion1_20_2:
|
|
// Check to see if a UUID was provided at all
|
|
hasUUID, err := ReadBoolean(buffer)
|
|
if err != nil {
|
|
return loginStart, errors.Wrap(err, "failed to read has uuid flag")
|
|
}
|
|
|
|
if !hasUUID {
|
|
break
|
|
}
|
|
fallthrough
|
|
case protocolVersion >= ProtocolVersion1_20_2:
|
|
// For 1.20.2 and later, the UUID is always present
|
|
playerUuid, err := ReadUuid(buffer)
|
|
if err != nil {
|
|
return loginStart, errors.Wrap(err, "failed to read player uuid")
|
|
}
|
|
loginStart.PlayerUuid = playerUuid
|
|
default:
|
|
// For versions before 1.19.2, the UUID is not present
|
|
}
|
|
|
|
return loginStart, nil
|
|
}
|