diff --git a/account_test.go b/account_test.go index 1d93a65..233ed09 100644 --- a/account_test.go +++ b/account_test.go @@ -16,7 +16,7 @@ func TestAccount(t *testing.T) { ts.Setup(config) defer ts.Teardown() - ts.CreateTestUser(ts.App, ts.Server, TEST_USERNAME) + ts.CreateTestUser(t, ts.App, ts.Server, TEST_USERNAME) t.Run("Test /users/profiles/minecraft/:playerName", ts.testAccountPlayerNameToID) t.Run("Test /profiles/minecraft", ts.makeTestAccountPlayerNamesToIDs("/profiles/minecraft")) @@ -33,7 +33,7 @@ func TestAccount(t *testing.T) { ts.Setup(config) defer ts.Teardown() - ts.CreateTestUser(ts.AuxApp, ts.AuxServer, TEST_USERNAME) + ts.CreateTestUser(t, ts.AuxApp, ts.AuxServer, TEST_USERNAME) t.Run("Test /users/profiles/minecraft/:playerName, fallback API server", ts.testAccountPlayerNameToIDFallback) t.Run("Test /profile/minecraft, fallback API server", ts.testAccountPlayerNamesToIDsFallback) diff --git a/api_test.go b/api_test.go index 65518f8..618c6fd 100644 --- a/api_test.go +++ b/api_test.go @@ -45,10 +45,10 @@ func TestAPI(t *testing.T) { func (ts *TestSuite) testAPIGetSelf(t *testing.T) { adminUsername := "admin" - admin, _ := ts.CreateTestUser(ts.App, ts.Server, adminUsername) + admin, _ := ts.CreateTestUser(t, ts.App, ts.Server, adminUsername) assert.True(t, admin.IsAdmin) - username2 := "user2" - user2, _ := ts.CreateTestUser(ts.App, ts.Server, username2) + username := "user" + user, _ := ts.CreateTestUser(t, ts.App, ts.Server, username) // admin (admin) should get a response rec := ts.Get(t, ts.Server, DRASL_API_PREFIX+"/user", nil, &admin.APIToken) @@ -58,20 +58,20 @@ func (ts *TestSuite) testAPIGetSelf(t *testing.T) { assert.Equal(t, admin.UUID, response.UUID) // user2 (not admin) should also get a response - rec = ts.Get(t, ts.Server, DRASL_API_PREFIX+"/user", nil, &user2.APIToken) + rec = ts.Get(t, ts.Server, DRASL_API_PREFIX+"/user", nil, &user.APIToken) assert.Equal(t, http.StatusOK, rec.Code) assert.Nil(t, json.NewDecoder(rec.Body).Decode(&response)) - assert.Equal(t, user2.UUID, response.UUID) + assert.Equal(t, user.UUID, response.UUID) assert.Nil(t, ts.App.DeleteUser(&GOD, admin)) - assert.Nil(t, ts.App.DeleteUser(&GOD, user2)) + assert.Nil(t, ts.App.DeleteUser(&GOD, user)) } func (ts *TestSuite) testAPIGetUsers(t *testing.T) { adminUsername := "admin" - admin, _ := ts.CreateTestUser(ts.App, ts.Server, adminUsername) + admin, _ := ts.CreateTestUser(t, ts.App, ts.Server, adminUsername) nonAdminUsername := "nonAdmin" - nonAdmin, _ := ts.CreateTestUser(ts.App, ts.Server, nonAdminUsername) + nonAdmin, _ := ts.CreateTestUser(t, ts.App, ts.Server, nonAdminUsername) // admin should get a response rec := ts.Get(t, ts.Server, DRASL_API_PREFIX+"/users", nil, &admin.APIToken) @@ -91,33 +91,33 @@ func (ts *TestSuite) testAPIGetUsers(t *testing.T) { } func (ts *TestSuite) testAPIGetUser(t *testing.T) { - username1 := "admin" - admin, _ := ts.CreateTestUser(ts.App, ts.Server, username1) - username2 := "user2" - user2, _ := ts.CreateTestUser(ts.App, ts.Server, username2) + adminUsername := "admin" + admin, _ := ts.CreateTestUser(t, ts.App, ts.Server, adminUsername) + nonAdminUsername := "nonAdmin" + nonAdmin, _ := ts.CreateTestUser(t, ts.App, ts.Server, nonAdminUsername) // admin should get a response - rec := ts.Get(t, ts.Server, DRASL_API_PREFIX+"/users/"+user2.UUID, nil, &admin.APIToken) + rec := ts.Get(t, ts.Server, DRASL_API_PREFIX+"/users/"+nonAdmin.UUID, nil, &admin.APIToken) assert.Equal(t, http.StatusOK, rec.Code) var response APIUser assert.Nil(t, json.NewDecoder(rec.Body).Decode(&response)) - assert.Equal(t, user2.UUID, response.UUID) + assert.Equal(t, nonAdmin.UUID, response.UUID) // user2 (not admin) should get a StatusForbidden - rec = ts.Get(t, ts.Server, DRASL_API_PREFIX+"/users/"+admin.UUID, nil, &user2.APIToken) + rec = ts.Get(t, ts.Server, DRASL_API_PREFIX+"/users/"+admin.UUID, nil, &nonAdmin.APIToken) assert.Equal(t, http.StatusForbidden, rec.Code) var err APIError assert.Nil(t, json.NewDecoder(rec.Body).Decode(&err)) assert.Nil(t, ts.App.DeleteUser(&GOD, admin)) - assert.Nil(t, ts.App.DeleteUser(&GOD, user2)) + assert.Nil(t, ts.App.DeleteUser(&GOD, nonAdmin)) } func (ts *TestSuite) testAPIDeleteUser(t *testing.T) { username1 := "admin" - admin, _ := ts.CreateTestUser(ts.App, ts.Server, username1) + admin, _ := ts.CreateTestUser(t, ts.App, ts.Server, username1) username2 := "user2" - user2, _ := ts.CreateTestUser(ts.App, ts.Server, username2) + user2, _ := ts.CreateTestUser(t, ts.App, ts.Server, username2) // user2 (not admin) should get a StatusForbidden rec := ts.Delete(t, ts.Server, DRASL_API_PREFIX+"/users/"+admin.UUID, nil, &user2.APIToken) @@ -139,7 +139,7 @@ func (ts *TestSuite) testAPIDeleteUser(t *testing.T) { func (ts *TestSuite) testAPIDeleteSelf(t *testing.T) { username := "user" - user, _ := ts.CreateTestUser(ts.App, ts.Server, username) + user, _ := ts.CreateTestUser(t, ts.App, ts.Server, username) rec := ts.Delete(t, ts.Server, DRASL_API_PREFIX+"/user", nil, &user.APIToken) assert.Equal(t, http.StatusNoContent, rec.Code) @@ -152,7 +152,7 @@ func (ts *TestSuite) testAPIDeleteSelf(t *testing.T) { func (ts *TestSuite) testAPIUpdateSelf(t *testing.T) { username := "user" - user, _ := ts.CreateTestUser(ts.App, ts.Server, username) + user, _ := ts.CreateTestUser(t, ts.App, ts.Server, username) assert.Equal(t, "en", user.PreferredLanguage) @@ -180,10 +180,10 @@ func (ts *TestSuite) testAPIUpdateSelf(t *testing.T) { func (ts *TestSuite) testAPIUpdateUser(t *testing.T) { adminUsername := "admin" - admin, _ := ts.CreateTestUser(ts.App, ts.Server, adminUsername) + admin, _ := ts.CreateTestUser(t, ts.App, ts.Server, adminUsername) username := "user" - user, _ := ts.CreateTestUser(ts.App, ts.Server, username) + user, _ := ts.CreateTestUser(t, ts.App, ts.Server, username) assert.Equal(t, ts.App.Constants.MaxPlayerCountUseDefault, user.MaxPlayerCount) @@ -203,12 +203,13 @@ func (ts *TestSuite) testAPIUpdateUser(t *testing.T) { assert.Nil(t, ts.App.DB.First(&user, "uuid = ?", user.UUID).Error) assert.Equal(t, newMaxPlayerCount, user.MaxPlayerCount) + assert.Nil(t, ts.App.DeleteUser(&GOD, admin)) assert.Nil(t, ts.App.DeleteUser(&GOD, user)) } func (ts *TestSuite) testAPICreateUser(t *testing.T) { adminUsername := "admin" - admin, _ := ts.CreateTestUser(ts.App, ts.Server, adminUsername) + admin, _ := ts.CreateTestUser(t, ts.App, ts.Server, adminUsername) createdUsername := "user2" @@ -258,7 +259,7 @@ func (ts *TestSuite) testAPICreateUser(t *testing.T) { func (ts *TestSuite) testAPIGetChallengeSkin(t *testing.T) { username := "user" - user, _ := ts.CreateTestUser(ts.App, ts.Server, username) + user, _ := ts.CreateTestUser(t, ts.App, ts.Server, username) ts.Get(t, ts.Server, DRASL_API_PREFIX+"/challenge-skin", nil, &user.APIToken) req := httptest.NewRequest(http.MethodGet, DRASL_API_PREFIX+"/challenge-skin", nil) @@ -272,13 +273,15 @@ func (ts *TestSuite) testAPIGetChallengeSkin(t *testing.T) { var challenge APIChallenge assert.Nil(t, json.NewDecoder(rec.Body).Decode(&challenge)) + + assert.Nil(t, ts.App.DeleteUser(&GOD, user)) } func (ts *TestSuite) testAPIGetPlayers(t *testing.T) { adminUsername := "admin" - admin, _ := ts.CreateTestUser(ts.App, ts.Server, adminUsername) + admin, _ := ts.CreateTestUser(t, ts.App, ts.Server, adminUsername) nonAdminUsername := "nonAdmin" - nonAdmin, _ := ts.CreateTestUser(ts.App, ts.Server, nonAdminUsername) + nonAdmin, _ := ts.CreateTestUser(t, ts.App, ts.Server, nonAdminUsername) // admin should get a response rec := ts.Get(t, ts.Server, DRASL_API_PREFIX+"/players", nil, &admin.APIToken) @@ -299,9 +302,9 @@ func (ts *TestSuite) testAPIGetPlayers(t *testing.T) { func (ts *TestSuite) testAPIGetPlayer(t *testing.T) { adminUsername := "admin" - admin, _ := ts.CreateTestUser(ts.App, ts.Server, adminUsername) + admin, _ := ts.CreateTestUser(t, ts.App, ts.Server, adminUsername) username := "user2" - user, _ := ts.CreateTestUser(ts.App, ts.Server, username) + user, _ := ts.CreateTestUser(t, ts.App, ts.Server, username) adminPlayer := admin.Players[0] player := user.Players[0] @@ -344,10 +347,10 @@ func (ts *TestSuite) testAPIGetPlayer(t *testing.T) { func (ts *TestSuite) testAPICreatePlayer(t *testing.T) { adminUsername := "admin" - admin, _ := ts.CreateTestUser(ts.App, ts.Server, adminUsername) + admin, _ := ts.CreateTestUser(t, ts.App, ts.Server, adminUsername) username := "user" - user, _ := ts.CreateTestUser(ts.App, ts.Server, username) + user, _ := ts.CreateTestUser(t, ts.App, ts.Server, username) assert.Equal(t, 1, len(user.Players)) assert.Equal(t, ts.App.Constants.MaxPlayerCountUseDefault, user.MaxPlayerCount) assert.Equal(t, 1, ts.Config.DefaultMaxPlayerCount) @@ -390,13 +393,13 @@ func (ts *TestSuite) testAPICreatePlayer(t *testing.T) { func (ts *TestSuite) testAPIUpdatePlayer(t *testing.T) { adminUsername := "admin" - admin, _ := ts.CreateTestUser(ts.App, ts.Server, adminUsername) + admin, _ := ts.CreateTestUser(t, ts.App, ts.Server, adminUsername) assert.Equal(t, 1, len(admin.Players)) adminPlayer := admin.Players[0] assert.Equal(t, adminUsername, adminPlayer.Name) username := "user" - user, _ := ts.CreateTestUser(ts.App, ts.Server, username) + user, _ := ts.CreateTestUser(t, ts.App, ts.Server, username) assert.Equal(t, 1, len(user.Players)) player := user.Players[0] assert.Equal(t, username, player.Name) @@ -450,9 +453,9 @@ func (ts *TestSuite) testAPIUpdatePlayer(t *testing.T) { func (ts *TestSuite) testAPIDeletePlayer(t *testing.T) { adminUsername := "admin" - admin, _ := ts.CreateTestUser(ts.App, ts.Server, adminUsername) + admin, _ := ts.CreateTestUser(t, ts.App, ts.Server, adminUsername) username := "user2" - user, _ := ts.CreateTestUser(ts.App, ts.Server, username) + user, _ := ts.CreateTestUser(t, ts.App, ts.Server, username) adminPlayer := admin.Players[0] player := user.Players[0] secondPlayer, err := ts.App.CreatePlayer( @@ -503,13 +506,14 @@ func (ts *TestSuite) testAPIDeletePlayer(t *testing.T) { assert.Equal(t, int64(0), count) assert.Nil(t, ts.App.DeleteUser(&GOD, admin)) + assert.Nil(t, ts.App.DeleteUser(&GOD, user)) } func (ts *TestSuite) testAPIGetInvites(t *testing.T) { username1 := "admin" - admin, _ := ts.CreateTestUser(ts.App, ts.Server, username1) + admin, _ := ts.CreateTestUser(t, ts.App, ts.Server, username1) username2 := "user2" - user2, _ := ts.CreateTestUser(ts.App, ts.Server, username2) + user2, _ := ts.CreateTestUser(t, ts.App, ts.Server, username2) _, err := ts.App.CreateInvite() assert.Nil(t, err) @@ -546,9 +550,9 @@ func (ts *TestSuite) testAPIGetInvites(t *testing.T) { func (ts *TestSuite) testAPIDeleteInvite(t *testing.T) { adminUsername := "admin" - admin, _ := ts.CreateTestUser(ts.App, ts.Server, adminUsername) + admin, _ := ts.CreateTestUser(t, ts.App, ts.Server, adminUsername) username := "user" - user, _ := ts.CreateTestUser(ts.App, ts.Server, username) + user, _ := ts.CreateTestUser(t, ts.App, ts.Server, username) invite, err := ts.App.CreateInvite() assert.Nil(t, err) @@ -574,9 +578,9 @@ func (ts *TestSuite) testAPIDeleteInvite(t *testing.T) { func (ts *TestSuite) testAPICreateInvite(t *testing.T) { username1 := "admin" - admin, _ := ts.CreateTestUser(ts.App, ts.Server, username1) + admin, _ := ts.CreateTestUser(t, ts.App, ts.Server, username1) username2 := "user2" - user2, _ := ts.CreateTestUser(ts.App, ts.Server, username2) + user2, _ := ts.CreateTestUser(t, ts.App, ts.Server, username2) var invites []Invite result := ts.App.DB.Find(&invites) diff --git a/auth_test.go b/auth_test.go index 0169fe0..94f21ef 100644 --- a/auth_test.go +++ b/auth_test.go @@ -17,8 +17,8 @@ func TestAuth(t *testing.T) { ts.Setup(config) defer ts.Teardown() - ts.CreateTestUser(ts.App, ts.Server, TEST_USERNAME) - ts.CreateTestUser(ts.App, ts.Server, TEST_OTHER_USERNAME) + ts.CreateTestUser(t, ts.App, ts.Server, TEST_USERNAME) + ts.CreateTestUser(t, ts.App, ts.Server, TEST_OTHER_USERNAME) t.Run("Test /", ts.testGetServerInfo) t.Run("Test /authenticate", ts.testAuthenticate) diff --git a/authlib_injector_test.go b/authlib_injector_test.go index 7eb770f..82a0e59 100644 --- a/authlib_injector_test.go +++ b/authlib_injector_test.go @@ -24,7 +24,7 @@ func TestAuthlibInjector(t *testing.T) { ts.Setup(config) defer ts.Teardown() - ts.CreateTestUser(ts.App, ts.Server, TEST_USERNAME) + ts.CreateTestUser(t, ts.App, ts.Server, TEST_USERNAME) t.Run("Test /authlib-injector", ts.testAuthlibInjectorRoot) } diff --git a/front_test.go b/front_test.go index 7e2194e..ff4c949 100644 --- a/front_test.go +++ b/front_test.go @@ -5,6 +5,7 @@ import ( "encoding/base64" "encoding/hex" "errors" + "github.com/google/uuid" "github.com/stretchr/testify/assert" "gorm.io/gorm" "html" @@ -20,9 +21,10 @@ import ( var FAKE_BROWSER_TOKEN = "deadbeef" -var EXISTING_PLAYER_NAME = "existing" +var EXISTING_PLAYER_NAME = "Existing" +var EXISTING_OTHER_PLAYER_NAME = "ExistingOther" -func setupRegistrationExistingPlayerTS(requireSkinVerification bool, requireInvite bool) *TestSuite { +func setupRegistrationExistingPlayerTS(t *testing.T, requireSkinVerification bool, requireInvite bool) *TestSuite { ts := &TestSuite{} auxConfig := testConfig() @@ -48,7 +50,8 @@ func setupRegistrationExistingPlayerTS(requireSkinVerification bool, requireInvi } ts.Setup(config) - ts.CreateTestUser(ts.AuxApp, ts.AuxServer, EXISTING_PLAYER_NAME) + ts.CreateTestUser(t, ts.AuxApp, ts.AuxServer, EXISTING_PLAYER_NAME) + ts.CreateTestUser(t, ts.AuxApp, ts.AuxServer, EXISTING_OTHER_PLAYER_NAME) return ts } @@ -93,6 +96,25 @@ func (ts *TestSuite) registrationShouldSucceed(t *testing.T, rec *httptest.Respo assert.Equal(t, ts.App.FrontEndURL+"/web/user", rec.Header().Get("Location")) } +func (ts *TestSuite) createPlayerShouldFail(t *testing.T, rec *httptest.ResponseRecorder, errorMessage string, returnURL string) { + assert.Equal(t, http.StatusSeeOther, rec.Code) + assert.Equal(t, errorMessage, getErrorMessage(rec)) + assert.Equal(t, returnURL, rec.Header().Get("Location")) +} + +func (ts *TestSuite) createPlayerShouldSucceed(t *testing.T, rec *httptest.ResponseRecorder) string { + assert.Equal(t, http.StatusSeeOther, rec.Code) + assert.Equal(t, "", getErrorMessage(rec)) + + returnURLExp := regexp.MustCompile("^" + regexp.QuoteMeta(ts.App.FrontEndURL+"/web/player/") + "(.+)$") + uuidMatch := returnURLExp.FindStringSubmatch(rec.Header().Get("Location")) + assert.True(t, uuidMatch != nil && len(uuidMatch) == 2) + uuid_ := uuidMatch[1] + _, err := uuid.Parse(uuid_) + assert.Nil(t, err) + return uuid_ +} + func (ts *TestSuite) updateUserShouldFail(t *testing.T, rec *httptest.ResponseRecorder, errorMessage string, returnURL string) { assert.Equal(t, http.StatusSeeOther, rec.Code) assert.Equal(t, errorMessage, getErrorMessage(rec)) @@ -180,6 +202,7 @@ func TestFront(t *testing.T) { defer ts.Teardown() t.Run("Test registration as new player, chosen UUID, chosen UUID allowed", ts.testRegistrationNewPlayerChosenUUID) + t.Run("Test create new player, chosen UUID, chosen UUID allowed", ts.testCreateNewPlayer) } { // Low rate limit @@ -215,7 +238,7 @@ func TestFront(t *testing.T) { auxConfig := testConfig() ts.SetupAux(auxConfig) - ts.CreateTestUser(ts.AuxApp, ts.AuxServer, EXISTING_PLAYER_NAME) + ts.CreateTestUser(t, ts.AuxApp, ts.AuxServer, EXISTING_PLAYER_NAME) config := testConfig() config.AllowTextureFromURL = true @@ -226,17 +249,27 @@ func TestFront(t *testing.T) { } { // Registration as existing player allowed, skin verification not required - ts := setupRegistrationExistingPlayerTS(false, false) + ts := setupRegistrationExistingPlayerTS( + t, + false, // requireSkinVerification + false, // requireInvite + ) defer ts.Teardown() t.Run("Test registration as existing player, no skin verification", ts.testRegistrationExistingPlayerNoVerification) + t.Run("Test import player, no skin verification", ts.testImportPlayerNoVerification) } { // Registration as existing player allowed, skin verification required - ts := setupRegistrationExistingPlayerTS(true, false) + ts := setupRegistrationExistingPlayerTS( + t, + true, // requireSkinVerification + false, // requireInvite + ) defer ts.Teardown() - t.Run("Test registration as existing player, with skin verification", ts.testRegistrationExistingPlayerWithVerification) + t.Run("Test registration as existing player, with skin verification", ts.testRegistrationExistingPlayerVerification) + t.Run("Test import player, with skin verification", ts.testImportPlayerVerification) } { // Invite required, new player @@ -251,7 +284,7 @@ func TestFront(t *testing.T) { } { // Invite required, existing player, skin verification - ts := setupRegistrationExistingPlayerTS(true, true) + ts := setupRegistrationExistingPlayerTS(t, true, true) defer ts.Teardown() t.Run("Test registration as existing player, with skin verification, invite only", ts.testRegistrationExistingPlayerInvite) @@ -420,7 +453,7 @@ func (ts *TestSuite) testRegistrationNewPlayer(t *testing.T) { func (ts *TestSuite) testRegistrationNewPlayerChosenUUIDNotAllowed(t *testing.T) { username := "noChosenUUID" - ts.CreateTestUser(ts.App, ts.Server, username) + ts.CreateTestUser(t, ts.App, ts.Server, username) uuid := "11111111-2222-3333-4444-555555555555" @@ -545,7 +578,7 @@ func (ts *TestSuite) testRegistrationNewPlayerInvite(t *testing.T) { } } -func (ts *TestSuite) solveSkinChallenge(t *testing.T, username string) *http.Cookie { +func (ts *TestSuite) solveRegisterChallenge(t *testing.T, username string) *http.Cookie { // Get challenge skin req := httptest.NewRequest(http.MethodGet, "/web/register-challenge?username="+username, nil) rec := httptest.NewRecorder() @@ -575,6 +608,36 @@ func (ts *TestSuite) solveSkinChallenge(t *testing.T, username string) *http.Coo return challengeToken } +func (ts *TestSuite) solveCreatePlayerChallenge(t *testing.T, playerName string) *http.Cookie { + // Get challenge skin + req := httptest.NewRequest(http.MethodGet, "/web/create-player-challenge?playerName="+playerName, nil) + rec := httptest.NewRecorder() + ts.Server.ServeHTTP(rec, req) + assert.Equal(t, http.StatusOK, rec.Code) + challengeToken := getCookie(rec, "challengeToken") + assert.NotEqual(t, "", challengeToken.Value) + + base64Exp, err := regexp.Compile("src=\"data:image\\/png;base64,([A-Za-z0-9+/&#;]*={0,2})\"") + assert.Nil(t, err) + match := base64Exp.FindStringSubmatch(rec.Body.String()) + assert.Equal(t, 2, len(match)) + // The base64 will come back HTML-escaped... + base64String := html.UnescapeString(match[1]) + + challengeSkin, err := base64.StdEncoding.DecodeString(base64String) + assert.Nil(t, err) + + var auxPlayer Player + result := ts.AuxApp.DB.First(&auxPlayer, "name = ?", playerName) + assert.Nil(t, result.Error) + + // Bypass the controller for setting the skin here, we can test that with the rest of /update + err = ts.AuxApp.SetSkinAndSave(&auxPlayer, bytes.NewReader(challengeSkin)) + assert.Nil(t, err) + + return challengeToken +} + func (ts *TestSuite) testRegistrationExistingPlayerInvite(t *testing.T) { username := EXISTING_PLAYER_NAME { @@ -613,7 +676,7 @@ func (ts *TestSuite) testRegistrationExistingPlayerInvite(t *testing.T) { assert.Nil(t, result.Error) inviteCount := len(invites) - challengeToken := ts.solveSkinChallenge(t, username) + challengeToken := ts.solveRegisterChallenge(t, username) returnURL := ts.App.FrontEndURL + "/web/registration?invite=" + invite.Code { // Registration with an invalid username should redirect to the @@ -634,7 +697,7 @@ func (ts *TestSuite) testRegistrationExistingPlayerInvite(t *testing.T) { form.Set("password", TEST_PASSWORD) form.Set("existingPlayer", "on") form.Set("inviteCode", invite.Code) - form.Set("challengeToken", "This is not a valid challenge token.") + form.Set("challengeToken", "invalid-challenge-token") form.Set("returnUrl", returnURL) rec := ts.PostForm(t, ts.Server, "/web/register", form, nil, nil) @@ -674,7 +737,7 @@ func (ts *TestSuite) testRegistrationExistingPlayerInvite(t *testing.T) { func (ts *TestSuite) testLoginLogout(t *testing.T) { username := "loginLogout" - ts.CreateTestUser(ts.App, ts.Server, username) + ts.CreateTestUser(t, ts.App, ts.Server, username) { // Login @@ -781,7 +844,104 @@ func (ts *TestSuite) testRegistrationExistingPlayerNoVerification(t *testing.T) } } -func (ts *TestSuite) testRegistrationExistingPlayerWithVerification(t *testing.T) { +func (ts *TestSuite) testImportPlayerNoVerification(t *testing.T) { + user, browserTokenCookie := ts.CreateTestUser(t, ts.App, ts.Server, "ImportPlayer") + user.MaxPlayerCount = ts.App.Constants.MaxPlayerCountUnlimited + assert.Nil(t, ts.App.DB.Save(&user).Error) + + returnURL := ts.App.FrontEndURL + "/web/user" + + form := url.Values{} + form.Set("userUuid", user.UUID) + form.Set("playerName", EXISTING_OTHER_PLAYER_NAME) + form.Set("existingPlayer", "on") + form.Set("returnUrl", returnURL) + rec := ts.PostForm(t, ts.Server, "/web/create-player", form, []http.Cookie{*browserTokenCookie}, nil) + createdUUID := ts.createPlayerShouldSucceed(t, rec) + + // Check that the new player was created with the same UUID as the player + // on the auxiliary server + var auxPlayer Player + result := ts.AuxApp.DB.First(&auxPlayer, "name = ?", EXISTING_OTHER_PLAYER_NAME) + assert.Nil(t, result.Error) + + var player Player + assert.Nil(t, ts.App.DB.First(&player, "uuid = ?", auxPlayer.UUID).Error) + assert.Equal(t, user.UUID, player.UserUUID) + assert.Equal(t, createdUUID, player.UUID) + + assert.Nil(t, ts.App.DB.First(&user, "uuid = ?", user.UUID).Error) + assert.Equal(t, 2, len(user.Players)) + + { + // Creating a new player should fail + form := url.Values{} + form.Set("userUuid", user.UUID) + form.Set("playerName", "SomeJunk") + form.Set("returnUrl", returnURL) + rec := ts.PostForm(t, ts.Server, "/web/create-player", form, []http.Cookie{*browserTokenCookie}, nil) + ts.createPlayerShouldFail(t, rec, "Creating a new player is not allowed.", returnURL) + } + { + // Creating a player with a missing existing player should fail + form := url.Values{} + form.Set("userUuid", user.UUID) + form.Set("playerName", "Nonexistent") + form.Set("existingPlayer", "on") + form.Set("returnUrl", returnURL) + rec := ts.PostForm(t, ts.Server, "/web/create-player", form, []http.Cookie{*browserTokenCookie}, nil) + ts.createPlayerShouldFail(t, rec, "Couldn't find your account, maybe try again: registration server returned error", returnURL) + } +} + +func (ts *TestSuite) testImportPlayerVerification(t *testing.T) { + user, browserTokenCookie := ts.CreateTestUser(t, ts.App, ts.Server, "ImportPlayer") + user.MaxPlayerCount = ts.App.Constants.MaxPlayerCountUnlimited + assert.Nil(t, ts.App.DB.Save(&user).Error) + + returnURL := ts.App.FrontEndURL + "/web/user" + + challengeToken := ts.solveCreatePlayerChallenge(t, EXISTING_OTHER_PLAYER_NAME) + + { + // Importing player should fail if we give the wrong challenge token + form := url.Values{} + form.Set("userUuid", user.UUID) + form.Set("playerName", EXISTING_OTHER_PLAYER_NAME) + form.Set("existingPlayer", "on") + form.Set("challengeToken", "invalid-challenge-token") + form.Set("returnUrl", returnURL) + rec := ts.PostForm(t, ts.Server, "/web/create-player", form, []http.Cookie{*browserTokenCookie}, nil) + ts.createPlayerShouldFail(t, rec, "Couldn't verify your skin, maybe try again: skin does not match", returnURL) + } + { + // Import should succeed when we give the correct challenge token + form := url.Values{} + form.Set("userUuid", user.UUID) + form.Set("playerName", EXISTING_OTHER_PLAYER_NAME) + form.Set("existingPlayer", "on") + form.Set("challengeToken", challengeToken.Value) + form.Set("returnUrl", returnURL) + rec := ts.PostForm(t, ts.Server, "/web/create-player", form, []http.Cookie{*browserTokenCookie}, nil) + createdUUID := ts.createPlayerShouldSucceed(t, rec) + + // Check that the new player was created with the same UUID as the player + // on the auxiliary server + var auxPlayer Player + result := ts.AuxApp.DB.First(&auxPlayer, "name = ?", EXISTING_OTHER_PLAYER_NAME) + assert.Nil(t, result.Error) + + var player Player + assert.Nil(t, ts.App.DB.First(&player, "uuid = ?", auxPlayer.UUID).Error) + assert.Equal(t, user.UUID, player.UserUUID) + assert.Equal(t, createdUUID, player.UUID) + + assert.Nil(t, ts.App.DB.First(&user, "uuid = ?", user.UUID).Error) + assert.Equal(t, 2, len(user.Players)) + } +} + +func (ts *TestSuite) testRegistrationExistingPlayerVerification(t *testing.T) { username := EXISTING_PLAYER_NAME returnURL := ts.App.FrontEndURL + "/web/registration" { @@ -804,14 +964,14 @@ func (ts *TestSuite) testRegistrationExistingPlayerWithVerification(t *testing.T assert.Equal(t, returnURL, rec.Header().Get("Location")) } { - challengeToken := ts.solveSkinChallenge(t, username) + challengeToken := ts.solveRegisterChallenge(t, username) { // Registration should fail if we give the wrong challenge token form := url.Values{} form.Set("username", username) form.Set("password", TEST_PASSWORD) form.Set("existingPlayer", "on") - form.Set("challengeToken", "This is not a valid challenge token.") + form.Set("challengeToken", "invalid-challenge-token") form.Set("returnUrl", returnURL) rec := ts.PostForm(t, ts.Server, "/web/register", form, nil, nil) @@ -846,7 +1006,7 @@ func (ts *TestSuite) testRegistrationExistingPlayerWithVerification(t *testing.T func (ts *TestSuite) testNewInviteDeleteInvite(t *testing.T) { username := "inviteAdmin" - user, browserTokenCookie := ts.CreateTestUser(ts.App, ts.Server, username) + user, browserTokenCookie := ts.CreateTestUser(t, ts.App, ts.Server, username) user.IsAdmin = true result := ts.App.DB.Save(&user) @@ -887,8 +1047,8 @@ func (ts *TestSuite) testNewInviteDeleteInvite(t *testing.T) { func (ts *TestSuite) testUserUpdate(t *testing.T) { username := "userUpdate" takenUsername := "userUpdateTaken" - user, browserTokenCookie := ts.CreateTestUser(ts.App, ts.Server, username) - takenUser, takenBrowserTokenCookie := ts.CreateTestUser(ts.App, ts.Server, takenUsername) + user, browserTokenCookie := ts.CreateTestUser(t, ts.App, ts.Server, username) + takenUser, takenBrowserTokenCookie := ts.CreateTestUser(t, ts.App, ts.Server, takenUsername) assert.Equal(t, "en", user.PreferredLanguage) user.IsAdmin = true @@ -979,9 +1139,9 @@ func (ts *TestSuite) testUserUpdate(t *testing.T) { func (ts *TestSuite) testPlayerUpdate(t *testing.T) { playerName := "playerUpdate" takenPlayerName := "pUpdateTaken" - user, browserTokenCookie := ts.CreateTestUser(ts.App, ts.Server, playerName) + user, browserTokenCookie := ts.CreateTestUser(t, ts.App, ts.Server, playerName) player := user.Players[0] - takenUser, takenBrowserTokenCookie := ts.CreateTestUser(ts.App, ts.Server, takenPlayerName) + takenUser, takenBrowserTokenCookie := ts.CreateTestUser(t, ts.App, ts.Server, takenPlayerName) takenPlayer := takenUser.Players[0] sum := blake3.Sum256(RED_SKIN) @@ -1132,9 +1292,27 @@ func (ts *TestSuite) testPlayerUpdate(t *testing.T) { } } +func (ts *TestSuite) testCreateNewPlayer(t *testing.T) { + username := "createNewPlayer1" + user, browserTokenCookie := ts.CreateTestUser(t, ts.App, ts.Server, username) + user.MaxPlayerCount = ts.App.Constants.MaxPlayerCountUnlimited + assert.Nil(t, ts.App.DB.Save(&user).Error) + + chosenUUID := "2f7b0267-2502-49f9-ba05-8f9c958df02c" + + form := url.Values{} + form.Set("userUuid", user.UUID) + form.Set("playerName", "createNewPlayer2") + form.Set("playerUuid", chosenUUID) + form.Set("returnUrl", ts.App.FrontEndURL+"/web/user") + rec := ts.PostForm(t, ts.Server, "/web/create-player", form, []http.Cookie{*browserTokenCookie}, nil) + createdUUID := ts.createPlayerShouldSucceed(t, rec) + assert.Equal(t, chosenUUID, createdUUID) +} + func (ts *TestSuite) testUpdateSkinsCapesNotAllowed(t *testing.T) { playerName := "updateNoSkinCape" - user, browserTokenCookie := ts.CreateTestUser(ts.App, ts.Server, playerName) + user, browserTokenCookie := ts.CreateTestUser(t, ts.App, ts.Server, playerName) player := user.Players[0] { @@ -1181,7 +1359,7 @@ func (ts *TestSuite) testUpdateSkinsCapesNotAllowed(t *testing.T) { func (ts *TestSuite) testTextureFromURL(t *testing.T) { // Test setting skin from URL username := "textureFromURL" - user, browserTokenCookie := ts.CreateTestUser(ts.App, ts.Server, username) + user, browserTokenCookie := ts.CreateTestUser(t, ts.App, ts.Server, username) player := user.Players[0] var auxPlayer Player @@ -1212,7 +1390,7 @@ func (ts *TestSuite) testDeleteAccount(t *testing.T) { usernameA := "deleteA" usernameB := "deleteB" - ts.CreateTestUser(ts.App, ts.Server, usernameA) + ts.CreateTestUser(t, ts.App, ts.Server, usernameA) { var user User result := ts.App.DB.First(&user, "username = ?", usernameA) @@ -1226,7 +1404,7 @@ func (ts *TestSuite) testDeleteAccount(t *testing.T) { assert.Nil(t, err) // Register usernameB - _, browserTokenCookie := ts.CreateTestUser(ts.App, ts.Server, usernameB) + _, browserTokenCookie := ts.CreateTestUser(t, ts.App, ts.Server, usernameB) // Check that usernameB has been created var otherUser User @@ -1306,13 +1484,13 @@ func (ts *TestSuite) testAdmin(t *testing.T) { returnURL := ts.App.FrontEndURL + "/web/admin" username := "admin" - user, browserTokenCookie := ts.CreateTestUser(ts.App, ts.Server, username) + user, browserTokenCookie := ts.CreateTestUser(t, ts.App, ts.Server, username) otherUsername := "adminOther" - otherUser, otherBrowserTokenCookie := ts.CreateTestUser(ts.App, ts.Server, otherUsername) + otherUser, otherBrowserTokenCookie := ts.CreateTestUser(t, ts.App, ts.Server, otherUsername) anotherUsername := "adminAnother" - anotherUser, anotherBrowserTokenCookie := ts.CreateTestUser(ts.App, ts.Server, anotherUsername) + anotherUser, anotherBrowserTokenCookie := ts.CreateTestUser(t, ts.App, ts.Server, anotherUsername) // Make `username` an admin user.IsAdmin = true diff --git a/player.go b/player.go index 15ae171..e9fe7a9 100644 --- a/player.go +++ b/player.go @@ -103,8 +103,7 @@ func (app *App) CreatePlayer( } maxPlayerCount := app.GetMaxPlayerCount(&user) - log.Println("mpc is", maxPlayerCount, "pc is", len(user.Players)) - if len(user.Players) >= maxPlayerCount && !callerIsAdmin { + if maxPlayerCount != Constants.MaxPlayerCountUnlimited && len(user.Players) >= maxPlayerCount && !callerIsAdmin { return Player{}, NewBadRequestUserError("You are only allowed to own %d player(s).", maxPlayerCount) } @@ -114,13 +113,13 @@ func (app *App) CreatePlayer( var playerUUID string if existingPlayer { - // Existing player registration + // Import player if !app.Config.RegistrationExistingPlayer.Allow && !callerIsAdmin { - return Player{}, NewBadRequestUserError("Registration from an existing player is not allowed.") + return Player{}, NewBadRequestUserError("Importing an existing player is not allowed.") } if chosenUUID != nil { - return Player{}, NewBadRequestUserError("Can't register from an existing player AND choose a UUID.") + return Player{}, NewBadRequestUserError("Can't import an existing player AND choose a UUID.") } var err error @@ -141,7 +140,7 @@ func (app *App) CreatePlayer( } else { // New player registration if !app.Config.RegistrationNewPlayer.Allow && !callerIsAdmin { - return Player{}, NewBadRequestUserError("Registration without some existing account is not allowed.") + return Player{}, NewBadRequestUserError("Creating a new player is not allowed.") } if chosenUUID == nil { diff --git a/services_test.go b/services_test.go index f8cde48..f563d8f 100644 --- a/services_test.go +++ b/services_test.go @@ -38,9 +38,9 @@ func TestServices(t *testing.T) { ts.Setup(config) defer ts.Teardown() - ts.CreateTestUser(ts.App, ts.Server, TEST_USERNAME) - ts.CreateTestUser(ts.App, ts.Server, SERVICES_EXISTING_USERNAME) - ts.CreateTestUser(ts.AuxApp, ts.AuxServer, TEST_USERNAME) + ts.CreateTestUser(t, ts.App, ts.Server, TEST_USERNAME) + ts.CreateTestUser(t, ts.App, ts.Server, SERVICES_EXISTING_USERNAME) + ts.CreateTestUser(t, ts.AuxApp, ts.AuxServer, TEST_USERNAME) // Set the red skin on the aux user var user User @@ -70,7 +70,7 @@ func TestServices(t *testing.T) { ts.Setup(config) defer ts.Teardown() - ts.CreateTestUser(ts.App, ts.Server, TEST_USERNAME) + ts.CreateTestUser(t, ts.App, ts.Server, TEST_USERNAME) t.Run("Test POST /minecraft/profile/skins, skins not allowed", ts.testServicesUploadSkinSkinsNotAllowed) } diff --git a/session_test.go b/session_test.go index 36fe105..79e1727 100644 --- a/session_test.go +++ b/session_test.go @@ -16,7 +16,7 @@ func TestSession(t *testing.T) { ts.Setup(config) defer ts.Teardown() - ts.CreateTestUser(ts.App, ts.Server, TEST_USERNAME) + ts.CreateTestUser(t, ts.App, ts.Server, TEST_USERNAME) t.Run("Test /session/minecraft/hasJoined", ts.testSessionHasJoined) t.Run("Test /session/minecraft/join", ts.testSessionJoin) diff --git a/test_suite_test.go b/test_suite_test.go index 99aff01..778ed1c 100644 --- a/test_suite_test.go +++ b/test_suite_test.go @@ -22,13 +22,13 @@ import ( "time" ) -const TEST_USERNAME = "username" +const TEST_USERNAME = "Username" const TEST_USERNAME_UPPERCASE = "USERNAME" -const TEST_PLAYER_NAME = "username" +const TEST_PLAYER_NAME = "Username" const TEST_PLAYER_NAME_UPPERCASE = "USERNAME" -const TEST_OTHER_USERNAME = "otherUsername" -const TEST_OTHER_PLAYER_NAME = "otherUsername" +const TEST_OTHER_USERNAME = "OtherUsername" +const TEST_OTHER_PLAYER_NAME = "OtherUsername" const TEST_PASSWORD = "password" @@ -149,20 +149,42 @@ func (ts *TestSuite) Teardown() { Check(err) } -func (ts *TestSuite) CreateTestUser(app *App, server *echo.Echo, username string) (*User, *http.Cookie) { +func (ts *TestSuite) CreateTestUser(t *testing.T, app *App, server *echo.Echo, username string) (*User, *http.Cookie) { + user, err := app.CreateUser( + &GOD, // caller + username, + TEST_PASSWORD, // password + false, + false, + nil, + nil, + nil, + nil, + false, // existingPlayer + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + ) + assert.Nil(t, err) + form := url.Values{} form.Set("username", username) form.Set("password", TEST_PASSWORD) - req := httptest.NewRequest(http.MethodPost, "/web/register", strings.NewReader(form.Encode())) + req := httptest.NewRequest(http.MethodPost, "/web/login", strings.NewReader(form.Encode())) req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - Check(req.ParseForm()) + assert.Nil(t, req.ParseForm()) rec := httptest.NewRecorder() server.ServeHTTP(rec, req) - var user User - app.DB.First(&user, "username = ?", username) - browserToken := getCookie(rec, "browserToken") + assert.NotNil(t, browserToken) + + assert.Nil(t, app.DB.First(&user, "username = ?", user.Username).Error) return &user, browserToken }