166 lines
3.8 KiB
Go
166 lines
3.8 KiB
Go
package bedrock
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/binary"
|
|
"encoding/json"
|
|
"strings"
|
|
|
|
"github.com/cubexteam/Frodding/net/info"
|
|
"github.com/cubexteam/Frodding/net/packets"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type LoginPacket struct {
|
|
*packets.Packet
|
|
Protocol int32
|
|
Username string
|
|
ClientUUID uuid.UUID
|
|
ClientXUID string
|
|
ClientID int64
|
|
ServerAddr string
|
|
Language string
|
|
SkinID string
|
|
SkinData []byte
|
|
CapeData []byte
|
|
GeometryName string
|
|
GeometryData string
|
|
}
|
|
|
|
func NewLoginPacket() *LoginPacket {
|
|
return &LoginPacket{
|
|
Packet: packets.NewPacket(info.IDLogin),
|
|
ClientUUID: uuid.New(),
|
|
}
|
|
}
|
|
|
|
func (pk *LoginPacket) Encode() {}
|
|
|
|
func (pk *LoginPacket) Decode() {
|
|
pk.Protocol = pk.GetInt()
|
|
pk.GetByte()
|
|
totalLen := int(pk.GetUVarInt())
|
|
if totalLen <= 0 || totalLen > pk.Remaining() {
|
|
pk.Username = "Player"
|
|
return
|
|
}
|
|
blob := pk.GetBytes(totalLen)
|
|
if len(blob) < 4 {
|
|
pk.Username = "Player"
|
|
return
|
|
}
|
|
chainLen := int(binary.LittleEndian.Uint32(blob[:4]))
|
|
if chainLen <= 0 || 4+chainLen > len(blob) {
|
|
pk.Username = "Player"
|
|
return
|
|
}
|
|
var chainData struct {
|
|
Chain []string `json:"chain"`
|
|
}
|
|
if err := json.Unmarshal(blob[4:4+chainLen], &chainData); err == nil {
|
|
for _, raw := range chainData.Chain {
|
|
pk.parseChain(raw)
|
|
}
|
|
}
|
|
offset := 4 + chainLen
|
|
if offset+4 > len(blob) {
|
|
if pk.Username == "" {
|
|
pk.Username = "Player"
|
|
}
|
|
return
|
|
}
|
|
clientLen := int(binary.LittleEndian.Uint32(blob[offset : offset+4]))
|
|
offset += 4
|
|
if clientLen > 0 && offset+clientLen <= len(blob) {
|
|
pk.parseClientData(string(blob[offset : offset+clientLen]))
|
|
}
|
|
if pk.Username == "" {
|
|
pk.Username = "Player"
|
|
}
|
|
}
|
|
|
|
func decodeJWTPayload(s string) ([]byte, error) {
|
|
b, err := base64.RawURLEncoding.DecodeString(s)
|
|
if err != nil {
|
|
switch len(s) % 4 {
|
|
case 2:
|
|
s += "=="
|
|
case 3:
|
|
s += "="
|
|
}
|
|
b, err = base64.URLEncoding.DecodeString(s)
|
|
}
|
|
return b, err
|
|
}
|
|
|
|
func (pk *LoginPacket) parseChain(raw string) {
|
|
parts := strings.Split(raw, ".")
|
|
if len(parts) < 2 {
|
|
return
|
|
}
|
|
payload, err := decodeJWTPayload(parts[1])
|
|
if err != nil {
|
|
return
|
|
}
|
|
var data struct {
|
|
ExtraData map[string]interface{} `json:"extraData"`
|
|
}
|
|
if err := json.Unmarshal(payload, &data); err != nil || data.ExtraData == nil {
|
|
return
|
|
}
|
|
if v, ok := data.ExtraData["displayName"]; ok {
|
|
if name, _ := v.(string); name != "" {
|
|
pk.Username = name
|
|
}
|
|
}
|
|
if v, ok := data.ExtraData["identity"]; ok {
|
|
if idStr, _ := v.(string); idStr != "" {
|
|
if u, err := uuid.Parse(idStr); err == nil {
|
|
pk.ClientUUID = u
|
|
}
|
|
}
|
|
}
|
|
if v, ok := data.ExtraData["XUID"]; ok {
|
|
pk.ClientXUID, _ = v.(string)
|
|
}
|
|
}
|
|
|
|
func (pk *LoginPacket) parseClientData(raw string) {
|
|
parts := strings.Split(raw, ".")
|
|
if len(parts) < 2 {
|
|
return
|
|
}
|
|
payload, err := decodeJWTPayload(parts[1])
|
|
if err != nil {
|
|
return
|
|
}
|
|
var data struct {
|
|
ClientRandomID int64 `json:"ClientRandomId"`
|
|
ServerAddress string `json:"ServerAddress"`
|
|
LanguageCode string `json:"LanguageCode"`
|
|
SkinID string `json:"SkinId"`
|
|
SkinData string `json:"SkinData"`
|
|
CapeData string `json:"CapeData"`
|
|
SkinGeomName string `json:"SkinGeometryName"`
|
|
SkinGeomData string `json:"SkinGeometry"`
|
|
}
|
|
if err := json.Unmarshal(payload, &data); err != nil {
|
|
return
|
|
}
|
|
pk.ClientID = data.ClientRandomID
|
|
pk.ServerAddr = data.ServerAddress
|
|
pk.Language = data.LanguageCode
|
|
if pk.Language == "" {
|
|
pk.Language = "en_US"
|
|
}
|
|
pk.SkinID = data.SkinID
|
|
pk.GeometryName = data.SkinGeomName
|
|
pk.SkinData, _ = base64.RawStdEncoding.DecodeString(data.SkinData)
|
|
pk.CapeData, _ = base64.RawStdEncoding.DecodeString(data.CapeData)
|
|
geomBytes, _ := base64.RawStdEncoding.DecodeString(data.SkinGeomData)
|
|
pk.GeometryData = string(geomBytes)
|
|
for len(pk.SkinData) < 8192 {
|
|
pk.SkinData = append(pk.SkinData, 0x00)
|
|
}
|
|
}
|