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") } - req := httptest.NewRequest("GET", url, nil) + if testCase.ForceResponse != "" { + q.Set("onUnknownProfileRespondWithUuid", testCase.ForceResponse) + } + + u.RawQuery = q.Encode() + req := httptest.NewRequest("GET", u.String(), nil) w := httptest.NewRecorder() if testCase.PanicErr != "" {