Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add cookies #507

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions pkg/edition/java/proto/packet/cookie/cookie_request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package cookie

import (
"io"

"go.minekube.com/common/minecraft/key"
"go.minekube.com/gate/pkg/edition/java/proto/util"
"go.minekube.com/gate/pkg/gate/proto"
)

type CookieRequest struct {
Key key.Key
}

func (c *CookieRequest) Encode(ctx *proto.PacketContext, wr io.Writer) error {
return util.WriteKey(wr, c.Key)
}

func (c *CookieRequest) Decode(ctx *proto.PacketContext, rd io.Reader) (err error) {
c.Key, err = util.ReadKey(rd)
return err
}
32 changes: 32 additions & 0 deletions pkg/edition/java/proto/packet/cookie/cookie_response.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package cookie

import (
"io"

"go.minekube.com/common/minecraft/key"
"go.minekube.com/gate/pkg/edition/java/proto/util"
"go.minekube.com/gate/pkg/gate/proto"
)

type CookieResponse struct {
Key key.Key
Payload []byte
}

func (c *CookieResponse) Encode(ctx *proto.PacketContext, wr io.Writer) error {
if err := util.WriteKey(wr, c.Key); err != nil {
return err
}

return util.WriteBytes(wr, c.Payload)
}

func (c *CookieResponse) Decode(ctx *proto.PacketContext, rd io.Reader) (err error) {
c.Key, err = util.ReadKey(rd)
if err != nil {
return err
}

c.Payload, err = util.ReadRawBytes(rd)
return err
}
32 changes: 32 additions & 0 deletions pkg/edition/java/proto/packet/cookie/cookie_store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package cookie

import (
"io"

"go.minekube.com/common/minecraft/key"
"go.minekube.com/gate/pkg/edition/java/proto/util"
"go.minekube.com/gate/pkg/gate/proto"
)

type CookieStore struct {
Key key.Key
Payload []byte
}

func (c *CookieStore) Encode(ctx *proto.PacketContext, wr io.Writer) error {
if err := util.WriteKey(wr, c.Key); err != nil {
return err
}

return util.WriteBytes(wr, c.Payload)
}

func (c *CookieStore) Decode(ctx *proto.PacketContext, rd io.Reader) (err error) {
c.Key, err = util.ReadKey(rd)
if err != nil {
return err
}

c.Payload, err = util.ReadBytes(rd)
return err
}
24 changes: 24 additions & 0 deletions pkg/edition/java/proto/state/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"go.minekube.com/gate/pkg/edition/java/proto/packet/bossbar"
"go.minekube.com/gate/pkg/edition/java/proto/packet/chat"
"go.minekube.com/gate/pkg/edition/java/proto/packet/config"
"go.minekube.com/gate/pkg/edition/java/proto/packet/cookie"
"go.minekube.com/gate/pkg/edition/java/proto/packet/plugin"
"go.minekube.com/gate/pkg/edition/java/proto/packet/tablist/legacytablist"
"go.minekube.com/gate/pkg/edition/java/proto/packet/tablist/playerinfo"
Expand Down Expand Up @@ -61,6 +62,9 @@ func init() {
Config.ServerBound.Register(&config.KnownPacks{},
m(0x07, version.Minecraft_1_20_5),
)
Config.ServerBound.Register(&cookie.CookieResponse{},
m(0x01, version.Minecraft_1_20_5),
)

Config.ClientBound.Register(&plugin.Message{},
m(0x00, version.Minecraft_1_20_2),
Expand Down Expand Up @@ -117,6 +121,12 @@ func init() {
Config.ClientBound.Register(&p.ServerLinks{},
m(0x10, version.Minecraft_1_21),
)
Config.ClientBound.Register(&cookie.CookieRequest{},
m(0x00, version.Minecraft_1_20_5),
)
Config.ClientBound.Register(&cookie.CookieStore{},
m(0x0A, version.Minecraft_1_20_5),
)

Login.ServerBound.Register(&p.ServerLogin{},
m(0x00, version.Minecraft_1_7_2))
Expand All @@ -126,6 +136,9 @@ func init() {
m(0x02, version.Minecraft_1_13))
Login.ServerBound.Register(&p.LoginAcknowledged{},
m(0x03, version.Minecraft_1_20_2))
Login.ServerBound.Register(&cookie.CookieResponse{},
m(0x04, version.Minecraft_1_20_5),
)

Login.ClientBound.Register(&p.Disconnect{},
m(0x00, version.Minecraft_1_7_2))
Expand All @@ -137,6 +150,8 @@ func init() {
m(0x03, version.Minecraft_1_8))
Login.ClientBound.Register(&p.LoginPluginMessage{},
m(0x04, version.Minecraft_1_13))
Login.ClientBound.Register(&cookie.CookieRequest{},
m(0x05, version.Minecraft_1_20_5))

Play.ServerBound.Fallback = false
Play.ClientBound.Fallback = false
Expand Down Expand Up @@ -259,6 +274,9 @@ func init() {
m(0x0C, version.Minecraft_1_20_5),
m(0x0E, version.Minecraft_1_21_2),
)
Play.ServerBound.Register(&cookie.CookieResponse{},
m(0x13, version.Minecraft_1_20_5),
)

Play.ClientBound.Register(&p.KeepAlive{},
m(0x00, version.Minecraft_1_7_2),
Expand Down Expand Up @@ -570,4 +588,10 @@ func init() {
Play.ClientBound.Register(&p.ServerLinks{},
m(0x7B, version.Minecraft_1_21),
)
Play.ClientBound.Register(&cookie.CookieRequest{},
m(0x16, version.Minecraft_1_20_5),
)
Play.ClientBound.Register(&cookie.CookieStore{},
m(0x72, version.Minecraft_1_20_5),
)
}
2 changes: 1 addition & 1 deletion pkg/edition/java/proto/util/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import (
"encoding/binary"
"errors"
"fmt"
"go.minekube.com/common/minecraft/key"
"io"
"math"
"strings"
"time"

"go.minekube.com/common/minecraft/key"
"go.minekube.com/gate/pkg/edition/java/profile"
"go.minekube.com/gate/pkg/util/uuid"
)
Expand Down
26 changes: 26 additions & 0 deletions pkg/edition/java/proxy/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"go.minekube.com/brigodier"
"go.minekube.com/common/minecraft/component"
"go.minekube.com/common/minecraft/key"

"go.minekube.com/gate/pkg/command"
"go.minekube.com/gate/pkg/edition/java/forge/modinfo"
Expand Down Expand Up @@ -1163,3 +1164,28 @@ func (r *ReadyEvent) Addr() string { return r.addr }
// Subscribe to this event to gracefully stop any subtasks,
// such as plugin dependencies.
type ShutdownEvent struct{}

// PlayerCookieResponseEvent is fired when a player sends the cookie requested from the server.
type PlayerCookieResponseEvent struct {
player Player
key key.Key
payload []byte
}

func newPlayerCookieResponseEvent(player Player, key key.Key, payload []byte) *PlayerCookieResponseEvent {
return &PlayerCookieResponseEvent{
player: player,
key: key,
payload: payload,
}
}

// Player returns the player from whom the cookie has been received.
func (c *PlayerCookieResponseEvent) Player() Player { return c.player }

// Key returns the provider of the responded cookie.
// For example: minecraft:cookie
func (c *PlayerCookieResponseEvent) Key() key.Key { return c.key }

// Payload returns the payload of the responded cookie.
func (c *PlayerCookieResponseEvent) Payload() []byte { return c.payload }
88 changes: 88 additions & 0 deletions pkg/edition/java/proxy/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/robinbraemer/event"

cfgpacket "go.minekube.com/gate/pkg/edition/java/proto/packet/config"
"go.minekube.com/gate/pkg/edition/java/proto/packet/cookie"
"go.minekube.com/gate/pkg/edition/java/proto/state"
"go.minekube.com/gate/pkg/edition/java/proto/state/states"
"go.minekube.com/gate/pkg/edition/java/proxy/internal/resourcepack"
Expand All @@ -23,6 +24,7 @@ import (
"github.com/go-logr/logr"
"go.minekube.com/common/minecraft/component"
"go.minekube.com/common/minecraft/component/codec/legacy"
"go.minekube.com/common/minecraft/key"
"go.uber.org/atomic"

"go.minekube.com/gate/pkg/edition/java/config"
Expand Down Expand Up @@ -108,6 +110,15 @@ type Player interface { // TODO convert to struct(?) bc this is a lot of methods
//
// Deprecated: Use PendingResourcePacks instead.
PendingResourcePack() *ResourcePackInfo

StoreCookie(key key.Key, payload []byte) error

// Sends request for a cookie which the player will respond to in the PlayerCookieResponseEvent.
RequestCookie(key key.Key) error

// Sends request for a cookie which the player will respond to in this function.
// It times out after 5 seconds if the player doesn't send any packet back.
RequestCookieWithResult(key key.Key) ([]byte, error)
}

type connectedPlayer struct {
Expand Down Expand Up @@ -143,6 +154,8 @@ type connectedPlayer struct {

serversToTry []string // names of servers to try if we got disconnected from previous
tryIndex int

CookieRequestTracker *cookieRequestTracker
}

var _ Player = (*connectedPlayer)(nil)
Expand Down Expand Up @@ -170,6 +183,9 @@ func newConnectedPlayer(
ping: ping,
permFunc: func(string) permission.TriState { return permission.Undefined },
playerKey: playerKey,
CookieRequestTracker: &cookieRequestTracker{
pending: make(map[string]chan []byte),
},
}
p.resourcePackHandler = resourcepack.NewHandler(p, p.eventMgr)
p.bundleHandler = &resourcepack.BundleDelimiterHandler{Player: p}
Expand Down Expand Up @@ -735,3 +751,75 @@ func (p *connectedPlayer) BackendInFlight() proto.PacketWriter {
}
return nil
}

func (p *connectedPlayer) StoreCookie(key key.Key, payload []byte) error {
if strings.TrimSpace(key.String()) == "" {
return errors.New("empty key")
}

if len(payload) > 5*1024 {
return errors.New("payload size exceeds 5 kiB")
}

if p.Protocol().Lower(version.Minecraft_1_20_5) {
return fmt.Errorf("%w: but player is on %s", ErrTransferUnsupportedClientProtocol, p.Protocol())
}

if p.State() != state.Play && p.State() != state.Config {
return errors.New("CookieStore packet can only be send in the Play and Configuration State")
}

return p.WritePacket(&cookie.CookieStore{
Key: key,
Payload: payload,
})
}

func (p *connectedPlayer) RequestCookie(key key.Key) error {
if strings.TrimSpace(key.String()) == "" {
return errors.New("empty key")
}

if p.Protocol().Lower(version.Minecraft_1_20_5) {
return fmt.Errorf("%w: but player is on %s", ErrTransferUnsupportedClientProtocol, p.Protocol())
}

return p.WritePacket(&cookie.CookieRequest{
Key: key,
})
}

type cookieRequestTracker struct {
mu sync.Mutex
pending map[string]chan []byte
}

func (p *connectedPlayer) RequestCookieWithResult(key key.Key) ([]byte, error) {
if strings.TrimSpace(key.String()) == "" {
return nil, errors.New("empty key")
}

if p.Protocol().Lower(version.Minecraft_1_20_5) {
return nil, fmt.Errorf("%w: but player is on %s", ErrTransferUnsupportedClientProtocol, p.Protocol())
}

responseChan := make(chan []byte, 1)
requestID := fmt.Sprintf("%s:%s", p.ID(), key)

p.CookieRequestTracker.mu.Lock()
p.CookieRequestTracker.pending[requestID] = responseChan
defer delete(p.CookieRequestTracker.pending, requestID)
p.CookieRequestTracker.mu.Unlock()

err := p.WritePacket(&cookie.CookieRequest{Key: key})
if err != nil {
return nil, err
}

select {
case response := <-responseChan:
return response, nil
case <-time.After(5 * time.Second):
return nil, errors.New("timeout waiting for response")
}
}
Loading