From 27c7b79b320958cf351f9f380ee486781031982a Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Tue, 11 Jun 2024 02:31:47 +0200 Subject: [PATCH] Added `onUnknownProfileRespondWithUuid` param to the `/profile` endpoint Introducing profiles endpoint was a mistake, but we had to deal with that mistake until I'll remove it. The Accounts service needs textures with a signature. But it is possible that a user has a fresh account and Chrly has not yet received the profile information. In this case we have no way to get textures for the player. Adding the onUnknownProfileRespondWithUuid parameter solves this problem. This is a bad solution and nobody should use it except Ely.by infrastructure. In v5 version the texture signature on Chrly will be removed. --- http/skinsystem.go | 27 ++++++++++++++++----- http/skinsystem_test.go | 54 +++++++++++++++++++++++++++++++++++------ 2 files changed, 67 insertions(+), 14 deletions(-) diff --git a/http/skinsystem.go b/http/skinsystem.go index ab94995..f15a7e5 100644 --- a/http/skinsystem.go +++ b/http/skinsystem.go @@ -190,8 +190,15 @@ func (ctx *Skinsystem) profileHandler(response http.ResponseWriter, request *htt } if profile == nil { - response.WriteHeader(http.StatusNoContent) - return + forceResponseWithUuid := request.URL.Query().Get("onUnknownProfileRespondWithUuid") + if forceResponseWithUuid == "" { + response.WriteHeader(http.StatusNoContent) + return + } + + profile = createEmptyProfile() + profile.Id = formatUuid(forceResponseWithUuid) + profile.Username = parseUsername(mux.Vars(request)["username"]) } texturesPropContent := &mojang.TexturesProp{ @@ -274,12 +281,10 @@ func (ctx *Skinsystem) getProfile(request *http.Request, proxy bool) (*profile, return nil, err } - profile := &profile{ - Textures: &mojang.TexturesResponse{}, // Field must be initialized to avoid "null" after json encoding - } + profile := createEmptyProfile() if skin != nil { - profile.Id = strings.Replace(skin.Uuid, "-", "", -1) + profile.Id = formatUuid(skin.Uuid) profile.Username = skin.Username } @@ -354,6 +359,16 @@ func (ctx *Skinsystem) getProfile(request *http.Request, proxy bool) (*profile, return profile, nil } +func createEmptyProfile() *profile { + return &profile{ + Textures: &mojang.TexturesResponse{}, // Field must be initialized to avoid "null" after json encoding + } +} + +func formatUuid(uuid string) string { + return strings.Replace(uuid, "-", "", -1) +} + func parseUsername(username string) string { return strings.TrimSuffix(username, ".png") } diff --git a/http/skinsystem_test.go b/http/skinsystem_test.go index 151d84f..a3e0de1 100644 --- a/http/skinsystem_test.go +++ b/http/skinsystem_test.go @@ -11,6 +11,7 @@ import ( "io/ioutil" "net/http" "net/http/httptest" + "net/url" "strings" "testing" "time" @@ -742,11 +743,12 @@ func (suite *skinsystemTestSuite) TestSignedTextures() { ***************************/ type profileTestCase struct { - Name string - Signed bool - BeforeTest func(suite *skinsystemTestSuite) - PanicErr string - AfterTest func(suite *skinsystemTestSuite, response *http.Response) + Name string + Signed bool + ForceResponse string + BeforeTest func(suite *skinsystemTestSuite) + PanicErr string + AfterTest func(suite *skinsystemTestSuite, response *http.Response) } var profileTestsCases = []*profileTestCase{ @@ -1028,6 +1030,36 @@ var profileTestsCases = []*profileTestCase{ suite.Equal("", string(body)) }, }, + { + Name: "Username not exists and Mojang profile unavailable, but there is a forceResponse param", + ForceResponse: "a12e41a4-e8e5-4503-987e-0adacf72ab93", + Signed: true, + BeforeTest: func(suite *skinsystemTestSuite) { + suite.SkinsRepository.On("FindSkinByUsername", "mock_username").Return(nil, nil) + suite.MojangTexturesProvider.On("GetForUsername", "mock_username").Once().Return(nil, nil) + suite.TexturesSigner.On("SignTextures", mock.Anything).Return("chrly signature", nil) + }, + AfterTest: func(suite *skinsystemTestSuite, response *http.Response) { + suite.Equal(200, response.StatusCode) + suite.Equal("application/json", response.Header.Get("Content-Type")) + body, _ := ioutil.ReadAll(response.Body) + suite.JSONEq(`{ + "id": "a12e41a4e8e54503987e0adacf72ab93", + "name": "mock_username", + "properties": [ + { + "name": "textures", + "signature": "chrly signature", + "value": "eyJ0aW1lc3RhbXAiOjE2MTQyMTQyMjMwMDAsInByb2ZpbGVJZCI6ImExMmU0MWE0ZThlNTQ1MDM5ODdlMGFkYWNmNzJhYjkzIiwicHJvZmlsZU5hbWUiOiJtb2NrX3VzZXJuYW1lIiwidGV4dHVyZXMiOnt9fQ==" + }, + { + "name": "texturesParamName", + "value": "texturesParamValue" + } + ] + }`, string(body)) + }, + }, { Name: "Username not exists and Mojang textures proxy returned an error", BeforeTest: func(suite *skinsystemTestSuite) { @@ -1060,12 +1092,18 @@ func (suite *skinsystemTestSuite) TestProfile() { suite.RunSubTest(testCase.Name, func() { testCase.BeforeTest(suite) - url := "http://chrly/profile/mock_username" + u, _ := url.Parse("http://chrly/profile/mock_username") + q := make(url.Values) if testCase.Signed { - url += "?unsigned=false" + q.Set("unsigned", "false") + } + + if testCase.ForceResponse != "" { + q.Set("onUnknownProfileRespondWithUuid", testCase.ForceResponse) } - req := httptest.NewRequest("GET", url, nil) + u.RawQuery = q.Encode() + req := httptest.NewRequest("GET", u.String(), nil) w := httptest.NewRecorder() if testCase.PanicErr != "" {