Remove username support

This commit is contained in:
Jacob Gunther
2023-04-22 18:19:34 -05:00
parent 4a201af734
commit f5a77a3eb3
3 changed files with 56 additions and 184 deletions

View File

@@ -8,12 +8,6 @@ import (
"net/http"
)
// MinecraftProfile is Minecraft profile information returned from the Mojang API.
type MinecraftProfile struct {
Username string `json:"name"`
UUID string `json:"id"`
}
// MinecraftProfileTextures is texture information about a Minecraft profile returned from the Mojang API.
type MinecraftProfileTextures struct {
UUID string `json:"id"`
@@ -45,47 +39,6 @@ type MinecraftDecodedTextures struct {
} `json:"textures"`
}
// UsernameToUUID converts a Minecraft username into a UUID using Mojang.
func UsernameToUUID(username string) (*MinecraftProfile, error) {
req, err := http.NewRequest("GET", fmt.Sprintf("https://api.mojang.com/users/profiles/minecraft/%s", username), nil)
if err != nil {
return nil, err
}
req.Header.Set("User-Agent", "mineatar.io Skin Render API")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
if resp.StatusCode == http.StatusNoContent || resp.StatusCode == http.StatusNotFound {
return nil, nil
}
return nil, fmt.Errorf("mojang: unexpected response: %s", resp.Status)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
response := &MinecraftProfile{}
if err = json.Unmarshal(body, response); err != nil {
return nil, err
}
return response, nil
}
// GetProfileTextures returns the textures of a Minecraft player from Mojang.
func GetProfileTextures(uuid string) (*MinecraftProfileTextures, error) {
req, err := http.NewRequest("GET", fmt.Sprintf("https://sessionserver.mojang.com/session/minecraft/profile/%s", uuid), nil)
@@ -118,13 +71,13 @@ func GetProfileTextures(uuid string) (*MinecraftProfileTextures, error) {
return nil, err
}
response := &MinecraftProfileTextures{}
response := MinecraftProfileTextures{}
if err = json.Unmarshal(body, response); err != nil {
if err = json.Unmarshal(body, &response); err != nil {
return nil, err
}
return response, nil
return &response, nil
}
// GetDecodedTexturesValue decodes the values from a MinecraftProfileTextures texture value.

View File

@@ -11,15 +11,14 @@ import (
func init() {
app.Get("/ping", PingHandler)
app.Get("/uuid/:user", UUIDHandler)
app.Get("/skin/:user", SkinHandler)
app.Get("/face/:user", FaceHandler)
app.Get("/head/:user", HeadHandler)
app.Get("/body/full/:user", FullBodyHandler)
app.Get("/body/front/:user", FrontBodyHandler)
app.Get("/body/back/:user", BackBodyHandler)
app.Get("/body/left/:user", LeftBodyHandler)
app.Get("/body/right/:user", RightBodyHandler)
app.Get("/skin/:uuid", SkinHandler)
app.Get("/face/:uuid", FaceHandler)
app.Get("/head/:uuid", HeadHandler)
app.Get("/body/full/:uuid", FullBodyHandler)
app.Get("/body/front/:uuid", FrontBodyHandler)
app.Get("/body/back/:uuid", BackBodyHandler)
app.Get("/body/left/:uuid", LeftBodyHandler)
app.Get("/body/right/:uuid", RightBodyHandler)
app.Use(NotFoundHandler)
}
@@ -28,18 +27,14 @@ func PingHandler(ctx *fiber.Ctx) error {
return ctx.SendStatus(http.StatusOK)
}
// FullBodyHandler is the API handler used for the `/body/full/:user` route.
// FullBodyHandler is the API handler used for the `/body/full/:uuid` route.
func FullBodyHandler(ctx *fiber.Ctx) error {
opts := ParseQueryParams(ctx, conf.Routes.FullBody)
uuid, ok, err := LookupUUID(ParseUserParam(ctx))
uuid, ok := ParseUUID(ExtractUUID(ctx))
if err != nil {
return err
}
if !ok && !opts.Fallback {
return ctx.SendStatus(http.StatusNotFound)
if !ok {
return SendUsernameDeprecation(ctx)
}
cacheKey := fmt.Sprintf("result:fullbody-%d-%t-%s", opts.Scale, opts.Overlay, uuid)
@@ -79,18 +74,14 @@ func FullBodyHandler(ctx *fiber.Ctx) error {
return ctx.Type("png").Send(data)
}
// FrontBodyHandler is the API handler used for the `/body/front/:user` route.
// FrontBodyHandler is the API handler used for the `/body/front/:uuid` route.
func FrontBodyHandler(ctx *fiber.Ctx) error {
opts := ParseQueryParams(ctx, conf.Routes.FrontBody)
uuid, ok, err := LookupUUID(ParseUserParam(ctx))
uuid, ok := ParseUUID(ExtractUUID(ctx))
if err != nil {
return err
}
if !ok && !opts.Fallback {
return ctx.SendStatus(http.StatusNotFound)
if !ok {
return SendUsernameDeprecation(ctx)
}
cacheKey := fmt.Sprintf("result:frontbody-%d-%t-%s", opts.Scale, opts.Overlay, uuid)
@@ -132,18 +123,14 @@ func FrontBodyHandler(ctx *fiber.Ctx) error {
return ctx.Type("png").Send(data)
}
// BackBodyHandler is the API handler used for the `/body/back/:user` route.
// BackBodyHandler is the API handler used for the `/body/back/:uuid` route.
func BackBodyHandler(ctx *fiber.Ctx) error {
opts := ParseQueryParams(ctx, conf.Routes.BackBody)
uuid, ok, err := LookupUUID(ParseUserParam(ctx))
uuid, ok := ParseUUID(ExtractUUID(ctx))
if err != nil {
return err
}
if !ok && !opts.Fallback {
return ctx.SendStatus(http.StatusNotFound)
if !ok {
return SendUsernameDeprecation(ctx)
}
cacheKey := fmt.Sprintf("result:backbody-%d-%t-%s", opts.Scale, opts.Overlay, uuid)
@@ -185,18 +172,14 @@ func BackBodyHandler(ctx *fiber.Ctx) error {
return ctx.Type("png").Send(data)
}
// LeftBodyHandler is the API handler used for the `/body/left/:user` route.
// LeftBodyHandler is the API handler used for the `/body/left/:uuid` route.
func LeftBodyHandler(ctx *fiber.Ctx) error {
opts := ParseQueryParams(ctx, conf.Routes.LeftBody)
uuid, ok, err := LookupUUID(ParseUserParam(ctx))
uuid, ok := ParseUUID(ExtractUUID(ctx))
if err != nil {
return err
}
if !ok && !opts.Fallback {
return ctx.SendStatus(http.StatusNotFound)
if !ok {
return SendUsernameDeprecation(ctx)
}
cacheKey := fmt.Sprintf("result:leftbody-%d-%t-%s", opts.Scale, opts.Overlay, uuid)
@@ -238,18 +221,14 @@ func LeftBodyHandler(ctx *fiber.Ctx) error {
return ctx.Type("png").Send(data)
}
// RightBodyHandler is the API handler used for the `/body/right/:user` route.
// RightBodyHandler is the API handler used for the `/body/right/:uuid` route.
func RightBodyHandler(ctx *fiber.Ctx) error {
opts := ParseQueryParams(ctx, conf.Routes.RightBody)
uuid, ok, err := LookupUUID(ParseUserParam(ctx))
uuid, ok := ParseUUID(ExtractUUID(ctx))
if err != nil {
return err
}
if !ok && !opts.Fallback {
return ctx.SendStatus(http.StatusNotFound)
if !ok {
return SendUsernameDeprecation(ctx)
}
cacheKey := fmt.Sprintf("result:rightbody-%d-%t-%s", opts.Scale, opts.Overlay, uuid)
@@ -291,18 +270,14 @@ func RightBodyHandler(ctx *fiber.Ctx) error {
return ctx.Type("png").Send(data)
}
// FaceHandler is the API handler used for the `/face/:user` route.
// FaceHandler is the API handler used for the `/face/:uuid` route.
func FaceHandler(ctx *fiber.Ctx) error {
opts := ParseQueryParams(ctx, conf.Routes.Face)
uuid, ok, err := LookupUUID(ParseUserParam(ctx))
uuid, ok := ParseUUID(ExtractUUID(ctx))
if err != nil {
return err
}
if !ok && !opts.Fallback {
return ctx.SendStatus(http.StatusNotFound)
if !ok {
return SendUsernameDeprecation(ctx)
}
cacheKey := fmt.Sprintf("result:face-%d-%t-%s", opts.Scale, opts.Overlay, uuid)
@@ -344,18 +319,14 @@ func FaceHandler(ctx *fiber.Ctx) error {
return ctx.Type("png").Send(data)
}
// HeadHandler is the API handler used for the `/head/:user` route.
// HeadHandler is the API handler used for the `/head/:uuid` route.
func HeadHandler(ctx *fiber.Ctx) error {
opts := ParseQueryParams(ctx, conf.Routes.Head)
uuid, ok, err := LookupUUID(ParseUserParam(ctx))
uuid, ok := ParseUUID(ExtractUUID(ctx))
if err != nil {
return err
}
if !ok && !opts.Fallback {
return ctx.SendStatus(http.StatusNotFound)
if !ok {
return SendUsernameDeprecation(ctx)
}
cacheKey := fmt.Sprintf("result:head-%d-%t-%s", opts.Scale, opts.Overlay, uuid)
@@ -397,18 +368,14 @@ func HeadHandler(ctx *fiber.Ctx) error {
return ctx.Type("png").Send(data)
}
// SkinHandler is the API handler used for the `/skin/:user` route.
// SkinHandler is the API handler used for the `/skin/:uuid` route.
func SkinHandler(ctx *fiber.Ctx) error {
opts := ParseQueryParams(ctx, conf.Routes.RawSkin)
uuid, ok, err := LookupUUID(ParseUserParam(ctx))
uuid, ok := ParseUUID(ctx.Params("uuid"))
if err != nil {
return err
}
if !ok && !opts.Fallback {
return ctx.SendStatus(http.StatusNotFound)
if !ok {
return SendUsernameDeprecation(ctx)
}
rawSkin, _, err := GetPlayerSkin(uuid)
@@ -430,21 +397,6 @@ func SkinHandler(ctx *fiber.Ctx) error {
return ctx.Type("png").Send(data)
}
// UUIDHandler is the API handler used for the `/uuid/:user` route.
func UUIDHandler(ctx *fiber.Ctx) error {
uuid, ok, err := LookupUUID(ctx.Params("user"))
if err != nil {
return err
}
if !ok {
return ctx.SendStatus(http.StatusNotFound)
}
return ctx.SendString(uuid)
}
// NotFoundHandler is the API handler used for any requests that do not match an existing route.
func NotFoundHandler(ctx *fiber.Ctx) error {
return ctx.SendStatus(http.StatusNotFound)

View File

@@ -21,7 +21,6 @@ type QueryParams struct {
Scale int `query:"scale"`
Download bool `query:"download"`
Overlay bool `query:"overlay"`
Fallback bool `query:"fallback"`
}
// FormatUUID returns the UUID string without any dashes.
@@ -29,41 +28,15 @@ func FormatUUID(uuid string) string {
return strings.ToLower(strings.ReplaceAll(uuid, "-", ""))
}
// LookupUUID returns the UUID of a player either by username or UUID, while attempting to use any cached values in the database.
func LookupUUID(value string) (string, bool, error) {
// ParseUUID parses the UUID given by the route parameters, and returns a boolean if the UUID is valid.
func ParseUUID(value string) (string, bool) {
value = FormatUUID(value)
if len(value) == 32 {
return value, true, nil
if len(value) != 32 {
return "", false
}
cacheKey := fmt.Sprintf("uuid:%s", value)
cache, ok, err := r.GetString(cacheKey)
if err != nil {
return "", false, err
}
if ok {
return cache, true, nil
}
profile, err := UsernameToUUID(value)
if err != nil {
return "", false, err
}
if profile == nil {
return "", false, nil
}
if err = r.Set(cacheKey, profile.UUID, conf.Cache.UUIDCacheDuration); err != nil {
return "", true, err
}
return profile.UUID, true, nil
return value, true
}
// FetchImage fetches the image by the URL and returns it as a parsed image.
@@ -95,12 +68,6 @@ func FetchImage(url string) (*image.NRGBA, error) {
// GetPlayerSkin fetches the skin of the Minecraft player by the UUID.
func GetPlayerSkin(uuid string) (*image.NRGBA, bool, error) {
uuid = FormatUUID(uuid)
if len(uuid) < 1 {
return skin.GetDefaultSkin(false), false, nil
}
cache, ok, err := r.GetNRGBA(fmt.Sprintf("skin:%s", uuid))
if err != nil {
@@ -221,7 +188,6 @@ func ParseQueryParams(ctx *fiber.Ctx, route RouteConfig) *QueryParams {
Scale: route.DefaultScale,
Download: route.DefaultDownload,
Overlay: route.DefaultOverlay,
Fallback: route.DefaultFallback,
}
if args.Has("scale") {
@@ -234,10 +200,6 @@ func ParseQueryParams(ctx *fiber.Ctx, route RouteConfig) *QueryParams {
response.Overlay = args.GetBool("overlay")
}
if args.Has("fallback") {
response.Fallback = args.GetBool("fallback")
}
if args.Has("download") {
response.Download = args.GetBool("download")
}
@@ -260,7 +222,12 @@ func GetInstanceID() (uint16, error) {
return 0, nil
}
// ParseUserParam returns the user name from the route param, allowing values such as "PassTheMayo.png" to be returned as "PassTheMayo".
func ParseUserParam(ctx *fiber.Ctx) string {
return strings.Split(ctx.Params("user"), ".")[0]
// ExtractUUID returns the user name from the route param, allowing values such as "PassTheMayo.png" to be returned as "PassTheMayo".
func ExtractUUID(ctx *fiber.Ctx) string {
return strings.Split(ctx.Params("uuid"), ".")[0]
}
// SendUsernameDeprecation sends a deprecation warning about usernames.
func SendUsernameDeprecation(ctx *fiber.Ctx) error {
return ctx.Status(http.StatusBadRequest).SendString("Deprecated: Username support has been deprecated since May 1st 2023, please use a valid UUID instead.")
}