Skip to content

Commit

Permalink
feat: skins from username/uuid
Browse files Browse the repository at this point in the history
  • Loading branch information
cosrnic authored and mworzala committed Oct 6, 2024
1 parent 2084433 commit 12fbe4c
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 13 deletions.
6 changes: 3 additions & 3 deletions cmd/mc/skin/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type addSkinOpts struct {
var (
ErrInvalidVariant = errors.New("invalid variant")

validationMap = map[string]bool{"classic": true, "slim": true}
validationMap = map[string]bool{"classic": true, "slim": true, "": true}
)

func newAddCmd(app *cli.App, account string) *cobra.Command {
Expand All @@ -47,7 +47,7 @@ func newAddCmd(app *cli.App, account string) *cobra.Command {

o.account = account

cmd.Flags().StringVar(&o.variant, "variant", "classic", "Skin variant [classic/slim]")
cmd.Flags().StringVar(&o.variant, "variant", "", "Skin variant [classic/slim] (defaults to classic)")
cmd.Flags().StringVar(&o.cape, "cape", "", "Cape name, 'none' to remove")
cmd.Flags().BoolVar(&o.apply, "apply", false, "Apply the skin")
cmd.Flags().BoolVar(&o.apply, "set", false, "Apply the skin")
Expand Down Expand Up @@ -112,7 +112,7 @@ func (o *addSkinOpts) execute(args []string) error {

skinData := args[0]

skin, err := o.app.SkinManager().CreateSkin(o.name, o.variant, skinData, o.cape)
skin, err := o.app.SkinManager().CreateSkin(o.name, o.variant, skinData, o.cape, client, ctx)
if err != nil {
return err
}
Expand Down
6 changes: 4 additions & 2 deletions internal/pkg/mojang/mojang.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ const (
)

var (
servicesApiUrl = "https://api.minecraftservices.com/"
profileApiUrl = servicesApiUrl + "minecraft/profile"
mojangApiUrl = "https://api.mojang.com/"
sessionserverUrl = "https://sessionserver.mojang.com/"
servicesApiUrl = "https://api.minecraftservices.com/"
profileApiUrl = servicesApiUrl + "minecraft/profile"
)

type Client struct {
Expand Down
24 changes: 22 additions & 2 deletions internal/pkg/mojang/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func (c *Client) ChangeSkin(ctx context.Context, accountToken string, texture st
}

func (c *Client) ChangeCape(ctx context.Context, accountToken string, cape string) (*ProfileInformationResponse, error) {
endpoint := "/capes/active"
endpoint := "capes/active"
headers := http.Header{}
headers.Set("Authorization", "Bearer "+accountToken)
headers.Set("Content-Type", "application/json")
Expand All @@ -100,9 +100,29 @@ func (c *Client) ChangeCape(ctx context.Context, accountToken string, cape strin
}

func (c *Client) DeleteCape(ctx context.Context, accountToken string) (*ProfileInformationResponse, error) {
endpoint := "/capes/active"
endpoint := "capes/active"
headers := http.Header{}
headers.Set("Authorization", "Bearer "+accountToken)

return delete[ProfileInformationResponse](c, ctx, endpoint, headers)
}

func (c *Client) UsernameToUuid(ctx context.Context, username string) (*UsernameToUuidResponse, error) {
oldUrl := c.baseUrl
c.baseUrl = mojangApiUrl // i dont like this but i cant think of any other way atm :(
endpoint := "users/profiles/minecraft/" + username

response, err := get[UsernameToUuidResponse](c, ctx, endpoint, http.Header{})
c.baseUrl = oldUrl
return response, err
}

func (c *Client) UuidToProfile(ctx context.Context, uuid string) (*UuidToProfileResponse, error) {
oldUrl := c.baseUrl
c.baseUrl = sessionserverUrl // i dont like this but i cant think of any other way atm :(
endpoint := "session/minecraft/profile/" + uuid

response, err := get[UuidToProfileResponse](c, ctx, endpoint, http.Header{})
c.baseUrl = oldUrl
return response, err
}
37 changes: 37 additions & 0 deletions internal/pkg/mojang/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,40 @@ type ProfileCape struct {
URL string `json:"url"`
Alias string `json:"alias"`
}

type UsernameToUuidResponse struct {
Name string `json:"name"`
Id string `json:"id"`
}

type UuidToProfileResponse struct {
Id string `json:"id"`
Name string `json:"name"`
Properties []ProfileProperties `json:"properties"`
Legacy bool `json:"legacy"`
}

type ProfileProperties struct {
Name string `json:"name"`
Value string `json:"value"`
Signature string `json:"signature"`
}

type TextureInformation struct {
Timestamp int `json:"timestamp"`
ProfileId string `json:"profileId"`
ProfileName string `json:"profileName"`
Textures Textures `json:"textures"`
}

type Textures struct {
Skin struct {
Url string `json:"url"`
Metadata struct {
Model string `json:"model"`
} `json:"metadata"`
} `json:"SKIN"`
Cape struct {
Url string `json:"url"`
} `json:"CAPE"`
}
69 changes: 63 additions & 6 deletions internal/pkg/skin/skin.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"time"

"github.com/mworzala/mc/internal/pkg/mojang"
"github.com/mworzala/mc/internal/pkg/util"
)

var (
Expand Down Expand Up @@ -48,7 +49,7 @@ func isImage(data []byte) bool {
}

type Manager interface {
CreateSkin(name string, variant string, skinData string, capeData string) (*Skin, error)
CreateSkin(name string, variant string, skinData string, capeData string, client *mojang.Client, ctx context.Context) (*Skin, error)
Skins() []*Skin
GetSkin(name string) (*Skin, error)
ApplySkin(s *Skin, client *mojang.Client, ctx context.Context, accountToken string) error
Expand Down Expand Up @@ -90,7 +91,7 @@ func NewManager(dataDir string) (Manager, error) {
return &manager, nil
}

func (m *fileManager) CreateSkin(name string, variant string, skinData string, capeData string) (*Skin, error) {
func (m *fileManager) CreateSkin(name string, variant string, skinData string, capeData string, client *mojang.Client, ctx context.Context) (*Skin, error) {
if !isValidName(name) {
return nil, ErrInvalidName
}
Expand All @@ -99,9 +100,8 @@ func (m *fileManager) CreateSkin(name string, variant string, skinData string, c
}

skin := &Skin{
Name: name,
Cape: capeData,
Variant: variant,
Name: name,
Cape: capeData,
}
if isFilePath(skinData) {
fileBytes, err := os.ReadFile(skinData)
Expand All @@ -116,7 +116,15 @@ func (m *fileManager) CreateSkin(name string, variant string, skinData string, c
base64Str := base64.StdEncoding.EncodeToString(fileBytes)
skin.Skin = base64Str
} else {
skin.Skin = skinData
texture, newVariant := getSkinInfo(skinData, variant, client, ctx)
skin.Skin = texture
skin.Variant = newVariant
}

if variant == "" && skin.Variant == "" {
skin.Variant = "classic"
} else if skin.Variant == "" {
skin.Variant = variant
}

skin.AddedDate = time.Now()
Expand All @@ -125,6 +133,55 @@ func (m *fileManager) CreateSkin(name string, variant string, skinData string, c
return skin, nil
}

func getSkinInfo(skinData string, variant string, client *mojang.Client, ctx context.Context) (string, string) {
if util.IsUUID(skinData) {
profile, err := client.UuidToProfile(ctx, skinData)
if err != nil {
return skinData, variant
}

base64TextureInfo, err := base64.StdEncoding.DecodeString(profile.Properties[0].Value)
if err != nil {
return skinData, variant
}
var textureInfo mojang.TextureInformation
err = json.Unmarshal(base64TextureInfo, &textureInfo)
if err != nil {
return skinData, variant
}
if variant == "" {
variant = textureInfo.Textures.Skin.Metadata.Model
}
return textureInfo.Textures.Skin.Url, variant

} else {
uuid, err := client.UsernameToUuid(ctx, skinData)
if err != nil {
return skinData, variant
}

profile, err := client.UuidToProfile(ctx, uuid.Id)
if err != nil {
return skinData, variant
}
base64texture := profile.Properties[0].Value

base64TextureInfo, err := base64.StdEncoding.DecodeString(base64texture)
if err != nil {
return skinData, variant
}
var textureInfo mojang.TextureInformation
err = json.Unmarshal(base64TextureInfo, &textureInfo)
if err != nil {
return skinData, variant
}
if variant == "" {
variant = textureInfo.Textures.Skin.Metadata.Model
}
return textureInfo.Textures.Skin.Url, variant
}
}

func (m *fileManager) Skins() (result []*Skin) {
for _, s := range m.AllSkins {
result = append(result, s)
Expand Down

0 comments on commit 12fbe4c

Please sign in to comment.