account and fuzzing

This commit is contained in:
adman
2026-01-04 16:58:46 +01:00
parent a1b7969080
commit 38e267348b
2 changed files with 219 additions and 3 deletions
+173
View File
@@ -107,9 +107,182 @@ func (a *Account) JoinServer(serverId string) (err error) {
return return
} }
type NameChangResp struct {
ChangedAt string `json:"changedAt"`
CreatedAt string `json:"createdAt"`
NameChangeAllowed bool `json:"nameChangeAllowed"`
}
func (a *Account) NameChangeInfo() (r NameChangResp, err error) {
err = a.doMcApiRequest("GET", "https://api.minecraftservices.com/minecraft/profile/namechange", nil, &r)
return
}
func NewOfflineAccount(name string) *Account { func NewOfflineAccount(name string) *Account {
return &Account{ return &Account{
Name: name, Name: name,
Uuid: crypto.FromOfflinePlayer(name), Uuid: crypto.FromOfflinePlayer(name),
} }
} }
// PlayerProfile represents the player's profile information
type PlayerProfile struct {
ID string `json:"id"`
Name string `json:"name"`
Skins []struct {
ID string `json:"id"`
State string `json:"state"`
URL string `json:"url"`
Variant string `json:"variant"`
} `json:"skins"`
Capes []struct {
ID string `json:"id"`
State string `json:"state"`
URL string `json:"url"`
Alias string `json:"alias"`
} `json:"capes"`
}
// QueryProfile queries the player's profile
func (a *Account) QueryProfile() (profile PlayerProfile, err error) {
err = a.doMcApiRequest("GET", BaseUrlApi+"/minecraft/profile", nil, &profile)
return
}
// PlayerAttributes represents the player's attributes
type PlayerAttributes struct {
Privileges struct {
OnlineChat struct {
Enabled bool `json:"enabled"`
} `json:"onlineChat"`
MultiplayerServer struct {
Enabled bool `json:"enabled"`
} `json:"multiplayerServer"`
MultiplayerRealms struct {
Enabled bool `json:"enabled"`
} `json:"multiplayerRealms"`
Telemetry struct {
Enabled bool `json:"enabled"`
} `json:"telemetry"`
OptionalTelemetry struct {
Enabled bool `json:"enabled"`
} `json:"optionalTelemetry"`
} `json:"privileges"`
ProfanityFilterPreferences struct {
ProfanityFilterOn bool `json:"profanityFilterOn"`
} `json:"profanityFilterPreferences"`
BanStatus struct {
BannedScopes map[string]struct {
BanID string `json:"banId"`
Expires string `json:"expires,omitempty"`
Reason string `json:"reason"`
ReasonMessage string `json:"reasonMessage"`
} `json:"bannedScopes"`
} `json:"banStatus"`
}
// QueryAttributes queries the player's attributes
func (a *Account) QueryAttributes() (attrs PlayerAttributes, err error) {
err = a.doMcApiRequest("GET", BaseUrlApi+"/player/attributes", nil, &attrs)
return
}
// ModifyAttributesRequest represents the request to modify player attributes
type ModifyAttributesRequest struct {
ProfanityFilterPreferences struct {
ProfanityFilterOn bool `json:"profanityFilterOn"`
} `json:"profanityFilterPreferences"`
}
// ModifyAttributes modifies the player's attributes
func (a *Account) ModifyAttributes(req ModifyAttributesRequest) (attrs PlayerAttributes, err error) {
err = a.doMcApiRequest("POST", BaseUrlApi+"/player/attributes", req, &attrs)
return
}
// BlockedUsers represents the list of blocked users
type BlockedUsers struct {
BlockedProfiles []string `json:"blockedProfiles"`
}
// GetBlocklist gets the list of blocked users
func (a *Account) GetBlocklist() (blocklist BlockedUsers, err error) {
err = a.doMcApiRequest("GET", BaseUrlApi+"/privacy/blocklist", nil, &blocklist)
return
}
// CheckNameAvailability checks if a name is available
type NameAvailability struct {
Status string `json:"status"` // DUPLICATE, AVAILABLE, NOT_ALLOWED
}
// CheckNameAvailability checks if a name is available
func (a *Account) CheckNameAvailability(name string) (avail NameAvailability, err error) {
err = a.doMcApiRequest("GET", BaseUrlApi+"/minecraft/profile/name/"+name+"/available", nil, &avail)
return
}
// ChangeName changes the player's name
func (a *Account) ChangeName(newName string) (profile PlayerProfile, err error) {
err = a.doMcApiRequest("PUT", BaseUrlApi+"/minecraft/profile/name/"+newName, nil, &profile)
return
}
// ChangeSkinRequest represents the request to change skin
type ChangeSkinRequest struct {
Variant string `json:"variant"` // "classic" or "slim"
URL string `json:"url"`
}
// ChangeSkin changes the player's skin
func (a *Account) ChangeSkin(req ChangeSkinRequest) (profile PlayerProfile, err error) {
err = a.doMcApiRequest("POST", BaseUrlApi+"/minecraft/profile/skins", req, &profile)
return
}
// ResetSkin resets the player's skin to default
func (a *Account) ResetSkin() (profile PlayerProfile, err error) {
err = a.doMcApiRequest("DELETE", BaseUrlApi+"/minecraft/profile/skins/active", nil, &profile)
return
}
// HideCape hides the player's active cape
func (a *Account) HideCape() (profile PlayerProfile, err error) {
err = a.doMcApiRequest("DELETE", BaseUrlApi+"/minecraft/profile/capes/active", nil, &profile)
return
}
// ShowCapeRequest represents the request to show a cape
type ShowCapeRequest struct {
CapeID string `json:"capeId"`
}
// ShowCape shows a specific cape
func (a *Account) ShowCape(capeID string) (profile PlayerProfile, err error) {
req := ShowCapeRequest{CapeID: capeID}
err = a.doMcApiRequest("PUT", BaseUrlApi+"/minecraft/profile/capes/active", req, &profile)
return
}
// CheckGiftCodeValidity checks if a gift code is valid
func (a *Account) CheckGiftCodeValidity(giftCode string) (valid bool, err error) {
url := BaseUrlApi + "/productvoucher/giftcode"
r, err := http.NewRequest("GET", url, nil)
if err != nil {
return false, err
}
r.Header.Set("Authorization", "Bearer "+a.Ygg)
resp, err := http.DefaultClient.Do(r)
if err != nil {
return false, err
}
defer resp.Body.Close()
// Returns HTTP 200 or 204 if valid, 404 if invalid
if resp.StatusCode == 200 || resp.StatusCode == 204 {
return true, nil
}
return false, nil
}
+46 -3
View File
@@ -6,6 +6,7 @@ import (
"testing" "testing"
"github.com/admin-else/strom/proto" "github.com/admin-else/strom/proto"
"github.com/admin-else/strom/proto_base"
"github.com/admin-else/strom/server" "github.com/admin-else/strom/server"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts" "github.com/google/go-cmp/cmp/cmpopts"
@@ -19,11 +20,13 @@ var nanIgnorer64 = cmp.Comparer(func(x, y float64) bool {
return (math.IsNaN(x) && math.IsNaN(y)) || x == y return (math.IsNaN(x) && math.IsNaN(y)) || x == y
}) })
func FuzzConn(f *testing.F) { func NewStateFuzzer(state proto_base.State, actor proto_base.Actor) func(t *testing.T, inbytes []byte) {
f.Fuzz(func(t *testing.T, inbytes []byte) { return func(t *testing.T, inbytes []byte) {
b1 := bytes.NewBuffer(inbytes) b1 := bytes.NewBuffer(inbytes)
b2 := bytes.NewBuffer(nil) b2 := bytes.NewBuffer(nil)
conn := server.Servee(nil) conn := server.Servee(nil)
conn.State = state
conn.Actor = actor
conn.R = b1 conn.R = b1
conn.W = b2 conn.W = b2
_ = conn.SetVersion("1.21.8") // cant fail _ = conn.SetVersion("1.21.8") // cant fail
@@ -55,5 +58,45 @@ func FuzzConn(f *testing.F) {
) )
} }
return return
}) }
}
func FuzzConnHandshakingToServer(f *testing.F) {
f.Fuzz(NewStateFuzzer(proto_base.Handshaking, proto_base.Server))
}
func FuzzConnHandshakingToClient(f *testing.F) {
f.Fuzz(NewStateFuzzer(proto_base.Handshaking, proto_base.Client))
}
func FuzzConnStatusToServer(f *testing.F) {
f.Fuzz(NewStateFuzzer(proto_base.Status, proto_base.Server))
}
func FuzzConnStatusToClient(f *testing.F) {
f.Fuzz(NewStateFuzzer(proto_base.Status, proto_base.Client))
}
func FuzzConnLoginToServer(f *testing.F) {
f.Fuzz(NewStateFuzzer(proto_base.Login, proto_base.Server))
}
func FuzzConnLoginToClient(f *testing.F) {
f.Fuzz(NewStateFuzzer(proto_base.Login, proto_base.Client))
}
func FuzzConnConfigToServer(f *testing.F) {
f.Fuzz(NewStateFuzzer(proto_base.Configuration, proto_base.Server))
}
func FuzzConnConfigToClient(f *testing.F) {
f.Fuzz(NewStateFuzzer(proto_base.Configuration, proto_base.Client))
}
func FuzzConnPlayToServer(f *testing.F) {
f.Fuzz(NewStateFuzzer(proto_base.Play, proto_base.Server))
}
func FuzzConnPlayToClient(f *testing.F) {
f.Fuzz(NewStateFuzzer(proto_base.Play, proto_base.Client))
} }