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

Added support for changing the nickname at the "preLogin" stage #233

Open
wants to merge 2 commits 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
55 changes: 35 additions & 20 deletions pkg/edition/java/proxy/events.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package proxy

import (
"net"

"errors"
"go.minekube.com/brigodier"
"go.minekube.com/common/minecraft/component"
"go.minekube.com/gate/pkg/command"
Expand All @@ -14,6 +13,7 @@ import (
"go.minekube.com/gate/pkg/edition/java/proxy/message"
"go.minekube.com/gate/pkg/edition/java/proxy/player"
"go.minekube.com/gate/pkg/util/permission"
"net"
)

// PingEvent is fired when a request for server information is sent by a remote client,
Expand Down Expand Up @@ -115,11 +115,13 @@ func NewGameProfileRequestEvent(
inbound Inbound,
original profile.GameProfile,
onlineMode bool,
use profile.GameProfile,
) *GameProfileRequestEvent {
return &GameProfileRequestEvent{
inbound: inbound,
original: original,
onlineMode: onlineMode,
use: use,
}
}

Expand All @@ -138,20 +140,17 @@ func (e *GameProfileRequestEvent) OnlineMode() bool {
return e.onlineMode
}

// GameProfile returns the game originalProfile that will be used to initialize the connection with.
// Should no originalProfile be set, the original originalProfile (given by the proxy) will be used.
func (e *GameProfileRequestEvent) GameProfile() profile.GameProfile {
return e.use
}

// SetGameProfile sets the profile to use for this connection.
func (e *GameProfileRequestEvent) SetGameProfile(p profile.GameProfile) {
e.use = p
}

// GameProfile returns the game profile that will be used to initialize the connection with.
// Should no profile be set, the original profile (given by the proxy) will be used.
func (e *GameProfileRequestEvent) GameProfile() profile.GameProfile {
if len(e.use.Name) == 0 {
return e.original
}
return e.use
}

//
//
//
Expand Down Expand Up @@ -228,18 +227,20 @@ func (p *PermissionsSetupEvent) SetFunc(fn permission.Func) {
// but before the proxy authenticates the player with Mojang or before the player's proxy connection
// is fully established (for offline mode).
type PreLoginEvent struct {
connection Inbound
username string
connection Inbound
originalUsername string

result PreLoginResult
reason component.Component
result PreLoginResult
useUsername string
reason component.Component
}

func newPreLoginEvent(conn Inbound, username string) *PreLoginEvent {
func newPreLoginEvent(conn Inbound, originalUsername string) *PreLoginEvent {
return &PreLoginEvent{
connection: conn,
username: username,
result: AllowedPreLogin,
connection: conn,
originalUsername: originalUsername,
useUsername: originalUsername,
result: AllowedPreLogin,
}
}

Expand All @@ -254,9 +255,23 @@ const (
ForceOfflineModePreLogin
)

// OriginalUsername returns the original username of the player.
func (e *PreLoginEvent) OriginalUsername() string {
return e.originalUsername
}

// Username returns the username of the player.
func (e *PreLoginEvent) Username() string {
return e.username
return e.useUsername
}

// SetUsername sets server username for the player.
func (e *PreLoginEvent) SetUsername(username string) error {
if !playerNameRegex.MatchString(username) {
return errors.New("username must matches ^[A-Za-z0-9_]{2,16}$")
}
e.useUsername = username
return nil
}

// Conn returns the inbound connection that is connecting to the proxy.
Expand Down
29 changes: 17 additions & 12 deletions pkg/edition/java/proxy/session_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ import (
type authSessionHandler struct {
*sessionHandlerDeps

log logr.Logger
inbound *loginInboundConn
profile *profile.GameProfile
onlineMode bool
log logr.Logger
inbound *loginInboundConn
originalProfile *profile.GameProfile
useProfile *profile.GameProfile
onlineMode bool

connectedPlayer *connectedPlayer
}
Expand All @@ -34,15 +35,17 @@ type playerRegistrar interface {

func newAuthSessionHandler(
inbound *loginInboundConn,
profile *profile.GameProfile,
originalProfile *profile.GameProfile,
useProfile *profile.GameProfile,
onlineMode bool,
sessionHandlerDeps *sessionHandlerDeps,
) netmc.SessionHandler {
return &authSessionHandler{
sessionHandlerDeps: sessionHandlerDeps,
log: logr.FromContextOrDiscard(inbound.Context()).WithName("authSession"),
inbound: inbound,
profile: profile,
originalProfile: originalProfile,
useProfile: useProfile,
onlineMode: onlineMode,
}
}
Expand All @@ -55,22 +58,24 @@ func (a *authSessionHandler) Disconnected() {
}

func (a *authSessionHandler) Activated() {
// Some connection types may need to alter the game profile.
gameProfile := *a.inbound.delegate.Type().AddGameProfileTokensIfRequired(
a.profile, a.config().Forwarding.Mode)
// Some connection types may need to alter the game originalProfile.
originalGameProfile := *a.inbound.delegate.Type().AddGameProfileTokensIfRequired(
a.originalProfile, a.config().Forwarding.Mode)
useGameProfile := *a.inbound.delegate.Type().AddGameProfileTokensIfRequired(
a.useProfile, a.config().Forwarding.Mode)

profileRequest := NewGameProfileRequestEvent(a.inbound, gameProfile, a.onlineMode)
profileRequest := NewGameProfileRequestEvent(a.inbound, originalGameProfile, a.onlineMode, useGameProfile)
a.eventMgr.Fire(profileRequest)
conn := a.inbound.delegate.MinecraftConn
if netmc.Closed(conn) {
return // Player disconnected after authentication
}
gameProfile = profileRequest.GameProfile()
useGameProfile = profileRequest.GameProfile()

// Initiate a regular connection and move over to it.
player := newConnectedPlayer(
conn,
&gameProfile,
&useGameProfile,
a.inbound.VirtualHost(),
a.onlineMode,
a.inbound.IdentifiedKey(),
Expand Down
44 changes: 31 additions & 13 deletions pkg/edition/java/proxy/session_initial_login.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ type initialLoginSessionHandler struct {

nopSessionHandler

currentState loginState
login *packet.ServerLogin
verify []byte
currentState loginState
originalLogin *packet.ServerLogin
useLogin *packet.ServerLogin
verify []byte
}

type loginState string
Expand Down Expand Up @@ -136,9 +137,9 @@ func (l *initialLoginSessionHandler) handleServerLogin(login *packet.ServerLogin
return
}
l.inbound.playerKey = playerKey
l.login = login
l.originalLogin = login

e := newPreLoginEvent(l.inbound, l.login.Username)
e := newPreLoginEvent(l.inbound, l.originalLogin.Username)
l.eventMgr.Fire(e)

if netmc.Closed(l.conn) {
Expand All @@ -150,6 +151,12 @@ func (l *initialLoginSessionHandler) handleServerLogin(login *packet.ServerLogin
return
}

l.useLogin = &packet.ServerLogin{
Username: e.Username(),
PlayerKey: login.PlayerKey,
HolderID: login.HolderID,
}

_ = l.inbound.loginEventFired(func() error {
if netmc.Closed(l.conn) {
return nil // Player was disconnected
Expand All @@ -159,7 +166,9 @@ func (l *initialLoginSessionHandler) handleServerLogin(login *packet.ServerLogin
(e.Result() == ForceOnlineModePreLogin || l.config().OnlineMode) {

if p, ok := netmc.Assert[GameProfileProvider](l.conn); ok {
sh := l.newAuthSessionHandler(l.inbound, p.GameProfile(), false)
useProfile := p.GameProfile()
useProfile.Name = l.useLogin.Username
sh := l.newAuthSessionHandler(l.inbound, p.GameProfile(), useProfile, false)
l.conn.SetSessionHandler(sh)
return nil
}
Expand All @@ -178,20 +187,26 @@ func (l *initialLoginSessionHandler) handleServerLogin(login *packet.ServerLogin
}

// Offline mode login
sh := l.newAuthSessionHandler(l.inbound, profile.NewOffline(l.login.Username), false)
sh := l.newAuthSessionHandler(
l.inbound,
profile.NewOffline(l.originalLogin.Username),
profile.NewOffline(l.useLogin.Username),
false)
l.conn.SetSessionHandler(sh)
return nil
})
}

func (l *initialLoginSessionHandler) newAuthSessionHandler(
inbound *loginInboundConn,
profile *profile.GameProfile,
originalProfile *profile.GameProfile,
useProfile *profile.GameProfile,
onlineMode bool,
) netmc.SessionHandler {
return newAuthSessionHandler(
inbound,
profile,
originalProfile,
useProfile,
onlineMode,
l.sessionHandlerDeps,
)
Expand All @@ -217,7 +232,7 @@ func (l *initialLoginSessionHandler) handleEncryptionResponse(resp *packet.Encry
}
l.currentState = encryptionResponseReceivedLoginState

if l.login == nil {
if l.originalLogin == nil {
l.log.V(1).Info("no ServerLogin packet received yet, disconnecting")
_ = l.conn.Close()
return
Expand Down Expand Up @@ -288,7 +303,7 @@ func (l *initialLoginSessionHandler) handleEncryptionResponse(resp *packet.Encry
ctx, cancel := context.WithTimeout(logr.NewContext(l.conn.Context(), log), 30*time.Second)
defer cancel()

authResp, err := authn.AuthenticateJoin(ctx, serverID, l.login.Username, optionalUserIP)
authResp, err := authn.AuthenticateJoin(ctx, serverID, l.originalLogin.Username, optionalUserIP)
if err != nil {
if errors.Is(err, context.Canceled) {
// The player disconnected before receiving we could authenticate.
Expand All @@ -306,16 +321,19 @@ func (l *initialLoginSessionHandler) handleEncryptionResponse(resp *packet.Encry
}

// Extract game profile from response.
gameProfile, err := authResp.GameProfile()
originalGameProfile, err := authResp.GameProfile()
if err != nil {
if netmc.CloseWith(l.conn, packet.DisconnectWith(unableAuthWithMojang)) == nil {
log.Error(err, "unable get GameProfile from Mojang authentication response")
}
return
}

useGameProfile := originalGameProfile
useGameProfile.Name = l.useLogin.Username

// All went well, initialize the session.
sh := l.newAuthSessionHandler(l.inbound, gameProfile, true)
sh := l.newAuthSessionHandler(l.inbound, originalGameProfile, useGameProfile, true)
l.conn.SetSessionHandler(sh)
}

Expand Down