mirror of
https://github.com/unmojang/drasl.git
synced 2025-08-03 10:56:06 -04:00
Look up fallback player ID using POST /profiles/minecraft
authlib-injector specifies POST /profiles/minecraft as the only available route for player name -> UUID, so we have to use it if we want to support authlib-injector-compatible fallback API servers.
This commit is contained in:
parent
7d2f20ca92
commit
b0eb50238b
41
account.go
41
account.go
@ -59,7 +59,7 @@ func (fallbackAPIServer *FallbackAPIServer) PlayerNamesToIDs(remainingLowerNames
|
||||
return responses
|
||||
}
|
||||
|
||||
func (fallbackAPIServer *FallbackAPIServer) PlayerNamesToIDsWorker() {
|
||||
func (app *App) PlayerNamesToIDsWorker(fallbackAPIServer *FallbackAPIServer) {
|
||||
// All communication with the POST /profiles/minecraft (a.k.a. POST
|
||||
// /minecraft/profile/lookup/bulk/byname) route on a fallback API server is
|
||||
// done by a single goroutine running this function. It buffers a queue of
|
||||
@ -93,6 +93,16 @@ func (fallbackAPIServer *FallbackAPIServer) PlayerNamesToIDsWorker() {
|
||||
}
|
||||
}
|
||||
|
||||
// Double-check for validity, invalid player names will spoil
|
||||
// the entire batch. We will assume that if a player name is
|
||||
// valid to Drasl, it is valid on all fallback API servers (if
|
||||
// this becomes a problem in the future, we may need a
|
||||
// FallbackAPIServer.ValidPlayerNameRegex.
|
||||
if app.ValidatePlayerName(job.LowerName) != nil {
|
||||
job.ReturnCh <- mo.None[PlayerNameToIDResponse]()
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := lowerNameToResponseChs[job.LowerName]; !ok {
|
||||
lowerNameQueue = append(lowerNameQueue, &job.LowerName)
|
||||
}
|
||||
@ -197,6 +207,17 @@ func AccountPlayerNameToID(app *App) func(c echo.Context) error {
|
||||
}
|
||||
|
||||
lowerName := strings.ToLower(playerName)
|
||||
if app.ValidatePlayerName(lowerName) != nil {
|
||||
// This error message is consistent with POST
|
||||
// https://api.mojang.com/users/profiles/minecraft/:playerName as
|
||||
// of 2025-04-03
|
||||
errorMessage := fmt.Sprintf("getProfileName.name: Invalid profile name")
|
||||
return &YggdrasilError{
|
||||
Code: http.StatusBadRequest,
|
||||
Error_: mo.Some("CONSTRAINT_VIOLATION"),
|
||||
ErrorMessage: mo.Some(errorMessage),
|
||||
}
|
||||
}
|
||||
|
||||
var player Player
|
||||
result := app.DB.First(&player, "name = ?", lowerName)
|
||||
@ -246,7 +267,8 @@ func AccountPlayerNamesToIDs(app *App) func(c echo.Context) error {
|
||||
Error_: mo.Some("CONSTRAINT_VIOLATION"),
|
||||
ErrorMessage: mo.Some(errorMessage),
|
||||
}
|
||||
} else if len(playerNames) > MAX_PLAYER_NAMES_TO_IDS {
|
||||
}
|
||||
if len(playerNames) > MAX_PLAYER_NAMES_TO_IDS {
|
||||
// This error message is consistent with POST
|
||||
// https://api.mojang.com/profiles/minecraft as of 2025-04-02
|
||||
errorMessage := fmt.Sprintf("getProfileName.profileNames: size must be between 0 and %d", MAX_PLAYER_NAMES_TO_IDS)
|
||||
@ -271,7 +293,20 @@ func AccountPlayerNamesToIDs(app *App) func(c echo.Context) error {
|
||||
ErrorMessage: mo.Some(errorMessage),
|
||||
}
|
||||
}
|
||||
remainingLowerNames.Add(strings.ToLower(playerName))
|
||||
|
||||
lowerName := strings.ToLower(playerName)
|
||||
if app.ValidatePlayerName(lowerName) != nil {
|
||||
// This error message is consistent with POST
|
||||
// https://api.mojang.com/profiles/minecraft as of 2025-04-03
|
||||
errorMessage := fmt.Sprintf("getProfileName.profileNames[%d].<list element>: Invalid profile name", i)
|
||||
return &YggdrasilError{
|
||||
Code: http.StatusBadRequest,
|
||||
Error_: mo.Some("CONSTRAINT_VIOLATION"),
|
||||
ErrorMessage: mo.Some(errorMessage),
|
||||
}
|
||||
}
|
||||
|
||||
remainingLowerNames.Add(lowerName)
|
||||
}
|
||||
|
||||
for _, lowerName := range remainingLowerNames.ToSlice() {
|
||||
|
50
common.go
50
common.go
@ -9,6 +9,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
mapset "github.com/deckarep/golang-set/v2"
|
||||
"github.com/dgraph-io/ristretto"
|
||||
"github.com/google/uuid"
|
||||
"github.com/labstack/echo/v4"
|
||||
@ -687,7 +688,7 @@ func (app *App) GetFallbackSkinTexturesProperty(player *Player) (*SessionProfile
|
||||
fallbackPlayer = player.FallbackPlayer
|
||||
}
|
||||
|
||||
for _, fallbackAPIServer := range app.Config.FallbackAPIServers {
|
||||
for _, fallbackAPIServer := range app.FallbackAPIServers {
|
||||
var id string
|
||||
if fallbackPlayerIsUUID {
|
||||
// If we have the UUID already, use it
|
||||
@ -695,38 +696,17 @@ func (app *App) GetFallbackSkinTexturesProperty(player *Player) (*SessionProfile
|
||||
} else {
|
||||
// Otherwise, we only know the player name. Query the fallback API
|
||||
// server to get the fallback player's UUID
|
||||
// TODO this should POST /profiles/minecraft instead to be authlib-injector-compatible
|
||||
reqURL, err := url.JoinPath(fallbackAPIServer.AccountURL, "/users/profiles/minecraft/", fallbackPlayer)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
lowerName := strings.ToLower(fallbackPlayer)
|
||||
fallbackResponses := fallbackAPIServer.PlayerNamesToIDs(mapset.NewSet(lowerName))
|
||||
if len(fallbackResponses) == 1 && strings.EqualFold(lowerName, fallbackResponses[0].Name) {
|
||||
id = fallbackResponses[0].ID
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
res, err := app.CachedGet(reqURL, fallbackAPIServer.CacheTTLSeconds)
|
||||
if err != nil {
|
||||
log.Printf("Couldn't access fallback API server at %s: %s\n", reqURL, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
// Be silent, 404s will be common here
|
||||
continue
|
||||
}
|
||||
|
||||
var playerResponse PlayerNameToIDResponse
|
||||
err = json.Unmarshal(res.BodyBytes, &playerResponse)
|
||||
if err != nil {
|
||||
log.Printf("Received invalid response from fallback API server at %s\n", reqURL)
|
||||
continue
|
||||
}
|
||||
id = playerResponse.ID
|
||||
}
|
||||
reqURL, err := url.JoinPath(fallbackAPIServer.SessionURL, "session/minecraft/profile", id)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
|
||||
res, err := app.CachedGet(reqURL+"?unsigned=false", fallbackAPIServer.CacheTTLSeconds)
|
||||
reqURL := fallbackAPIServer.Config.SessionURL + "/session/minecraft/profile/" + url.PathEscape(id)
|
||||
res, err := app.CachedGet(reqURL+"?unsigned=false", fallbackAPIServer.Config.CacheTTLSeconds)
|
||||
if err != nil {
|
||||
log.Printf("Couldn't access fallback API server at %s: %s\n", reqURL, err)
|
||||
continue
|
||||
@ -806,11 +786,7 @@ func (app *App) GetDefaultSkinTexture(player *Player) *texture {
|
||||
return nil
|
||||
}
|
||||
|
||||
defaultSkinURL, err := url.JoinPath(app.FrontEndURL, "web/texture/default-skin/"+filename)
|
||||
if err != nil {
|
||||
log.Printf("Error generating default skin URL for file %s\n", *defaultSkinPath)
|
||||
return nil
|
||||
}
|
||||
defaultSkinURL := app.FrontEndURL + "/web/texture/default-skin/" + url.PathEscape(filename)
|
||||
|
||||
skinModel := SkinModelClassic
|
||||
if slimSkinRegex.MatchString(*defaultSkinPath) {
|
||||
@ -844,11 +820,7 @@ func (app *App) GetDefaultCapeTexture(player *Player) *texture {
|
||||
return nil
|
||||
}
|
||||
|
||||
defaultCapeURL, err := url.JoinPath(app.FrontEndURL, "web/texture/default-cape/"+filename)
|
||||
if err != nil {
|
||||
log.Printf("Error generating default cape URL for file %s\n", *defaultCapePath)
|
||||
return nil
|
||||
}
|
||||
defaultCapeURL := app.FrontEndURL + "/web/texture/default-cape/" + url.PathEscape(filename)
|
||||
|
||||
return &texture{
|
||||
URL: defaultCapeURL,
|
||||
|
Loading…
x
Reference in New Issue
Block a user