Delete skin/cape

This commit is contained in:
Evan Goode 2023-05-16 00:24:55 -04:00
parent 1ac386f206
commit de40a0cde0
7 changed files with 128 additions and 70 deletions

View File

@ -119,6 +119,7 @@ func AccountPlayerNamesToIDs(app *App) func(c echo.Context) error {
} }
} }
// /user/security/location
func AccountVerifySecurityLocation(app *App) func(c echo.Context) error { func AccountVerifySecurityLocation(app *App) func(c echo.Context) error {
return func(c echo.Context) error { return func(c echo.Context) error {
return c.NoContent(http.StatusNoContent) return c.NoContent(http.StatusNoContent)

View File

@ -188,6 +188,12 @@ func ValidateCape(app *App, reader io.Reader) (io.Reader, error) {
} }
func SetSkin(app *App, user *User, reader io.Reader) error { func SetSkin(app *App, user *User, reader io.Reader) error {
oldSkinHash := UnmakeNullString(&user.SkinHash)
if reader == nil {
// handle resetting skin to "no skin"
user.SkinHash = MakeNullString(nil)
} else {
limitedReader := io.LimitReader(reader, 10e6) limitedReader := io.LimitReader(reader, 10e6)
// It's fine to read the whole skin into memory here, they will almost // It's fine to read the whole skin into memory here, they will almost
@ -207,7 +213,6 @@ func SetSkin(app *App, user *User, reader io.Reader) error {
return err return err
} }
oldSkinHash := UnmakeNullString(&user.SkinHash)
user.SkinHash = MakeNullString(&hash) user.SkinHash = MakeNullString(&hash)
// TODO deal with race conditions here // TODO deal with race conditions here
@ -222,14 +227,15 @@ func SetSkin(app *App, user *User, reader io.Reader) error {
if err != nil { if err != nil {
return err return err
} }
}
err = app.DB.Save(&user).Error err := app.DB.Save(&user).Error
if err != nil { if err != nil {
return err return err
} }
if oldSkinHash != nil { if oldSkinHash != nil {
err = DeleteSkin(app, hash) err = DeleteSkinIfUnused(app, *oldSkinHash)
if err != nil { if err != nil {
return err return err
} }
@ -239,6 +245,12 @@ func SetSkin(app *App, user *User, reader io.Reader) error {
} }
func SetCape(app *App, user *User, reader io.Reader) error { func SetCape(app *App, user *User, reader io.Reader) error {
oldCapeHash := UnmakeNullString(&user.CapeHash)
if reader == nil {
// handle resetting cape to "no cape"
user.CapeHash = MakeNullString(nil)
} else {
limitedReader := io.LimitReader(reader, 10e6) limitedReader := io.LimitReader(reader, 10e6)
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
@ -256,7 +268,6 @@ func SetCape(app *App, user *User, reader io.Reader) error {
return err return err
} }
oldCapeHash := UnmakeNullString(&user.CapeHash)
user.CapeHash = MakeNullString(&hash) user.CapeHash = MakeNullString(&hash)
// TODO deal with race conditions here // TODO deal with race conditions here
@ -271,14 +282,15 @@ func SetCape(app *App, user *User, reader io.Reader) error {
if err != nil { if err != nil {
return err return err
} }
}
err = app.DB.Save(&user).Error err := app.DB.Save(&user).Error
if err != nil { if err != nil {
return err return err
} }
if oldCapeHash != nil { if oldCapeHash != nil {
err = DeleteCape(app, hash) err = DeleteCapeIfUnused(app, *oldCapeHash)
if err != nil { if err != nil {
return err return err
} }
@ -288,7 +300,7 @@ func SetCape(app *App, user *User, reader io.Reader) error {
} }
// Delete skin if not in use // Delete skin if not in use
func DeleteSkin(app *App, hash string) error { func DeleteSkinIfUnused(app *App, hash string) error {
var inUse bool var inUse bool
err := app.DB.Model(User{}). err := app.DB.Model(User{}).
Select("count(*) > 0"). Select("count(*) > 0").
@ -307,7 +319,7 @@ func DeleteSkin(app *App, hash string) error {
} }
// Delete cape if not in use // Delete cape if not in use
func DeleteCape(app *App, hash string) error { func DeleteCapeIfUnused(app *App, hash string) error {
var inUse bool var inUse bool
err := app.DB.Model(User{}). err := app.DB.Model(User{}).
Select("count(*) > 0"). Select("count(*) > 0").

View File

@ -202,7 +202,9 @@ func FrontUpdate(app *App) func(c echo.Context) error {
preferredLanguage := c.FormValue("preferredLanguage") preferredLanguage := c.FormValue("preferredLanguage")
skinModel := c.FormValue("skinModel") skinModel := c.FormValue("skinModel")
skinURL := c.FormValue("skinUrl") skinURL := c.FormValue("skinUrl")
deleteSkin := c.FormValue("deleteSkin")
capeURL := c.FormValue("capeUrl") capeURL := c.FormValue("capeUrl")
deleteCape := c.FormValue("deleteCape")
if err := ValidatePlayerName(app, playerName); err != nil { if err := ValidatePlayerName(app, playerName); err != nil {
setErrorMessage(&c, fmt.Sprintf("Invalid player name: %s", err)) setErrorMessage(&c, fmt.Sprintf("Invalid player name: %s", err))
@ -269,8 +271,13 @@ func FrontUpdate(app *App) func(c echo.Context) error {
setErrorMessage(&c, fmt.Sprintf("Error using that skin: %s", err)) setErrorMessage(&c, fmt.Sprintf("Error using that skin: %s", err))
return c.Redirect(http.StatusSeeOther, returnURL) return c.Redirect(http.StatusSeeOther, returnURL)
} }
err = SetSkin(app, user, validSkinHandle)
err = SetSkin(app, user, validSkinHandle)
if err != nil {
return nil
}
} else if deleteSkin == "on" {
err := SetSkin(app, user, nil)
if err != nil { if err != nil {
return nil return nil
} }
@ -308,6 +315,11 @@ func FrontUpdate(app *App) func(c echo.Context) error {
} }
err = SetCape(app, user, validCapeHandle) err = SetCape(app, user, validCapeHandle)
if err != nil {
return nil
}
} else if deleteCape == "on" {
err := SetCape(app, user, nil)
if err != nil { if err != nil {
return nil return nil
} }
@ -758,14 +770,14 @@ func FrontDeleteAccount(app *App) func(c echo.Context) error {
app.DB.Delete(&user) app.DB.Delete(&user)
if oldSkinHash != nil { if oldSkinHash != nil {
err := DeleteSkin(app, *oldSkinHash) err := DeleteSkinIfUnused(app, *oldSkinHash)
if err != nil { if err != nil {
return err return err
} }
} }
if oldCapeHash != nil { if oldCapeHash != nil {
err := DeleteCape(app, *oldCapeHash) err := DeleteCapeIfUnused(app, *oldCapeHash)
if err != nil { if err != nil {
return err return err
} }

View File

@ -142,6 +142,8 @@ func GetServicesServer(app *App) *echo.Echo {
e.Any("/player/attributes", ServicesPlayerAttributes(app)) e.Any("/player/attributes", ServicesPlayerAttributes(app))
e.Any("/player/certificates", ServicesPlayerCertificates(app)) e.Any("/player/certificates", ServicesPlayerCertificates(app))
e.POST("/minecraft/profile/skins", ServicesUploadSkin(app)) e.POST("/minecraft/profile/skins", ServicesUploadSkin(app))
e.DELETE("/minecraft/profile/skins/active", ServicesDeleteSkin(app))
e.DELETE("/minecraft/profile/capes/active", ServicesDeleteCape(app))
return e return e
} }

View File

@ -292,3 +292,27 @@ func ServicesUploadSkin(app *App) func(c echo.Context) error {
return c.NoContent(http.StatusOK) return c.NoContent(http.StatusOK)
}) })
} }
// /minecraft/profile/skins/active
func ServicesDeleteSkin(app *App) func(c echo.Context) error {
return withBearerAuthentication(app, func(c echo.Context, user *User) error {
err := SetSkin(app, user, nil)
if err != nil {
return err
}
return c.NoContent(http.StatusOK)
})
}
// /minecraft/profile/capes/active
func ServicesDeleteCape(app *App) func(c echo.Context) error {
return withBearerAuthentication(app, func(c echo.Context, user *User) error {
err := SetCape(app, user, nil)
if err != nil {
return err
}
return c.NoContent(http.StatusOK)
})
}

View File

@ -2,7 +2,6 @@ package main
import ( import (
"errors" "errors"
"fmt"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"gorm.io/gorm" "gorm.io/gorm"
"log" "log"

View File

@ -75,13 +75,17 @@
</p> </p>
<h4>Skin</h4> <h4>Skin</h4>
<p> <p>
<label for="skinUrl">URL to skin file</label><br> <label for="skin-url">URL to skin file</label><br>
<input type="text" name="skinUrl" id="skin-url" placeholder="Leave blank to keep"> <input type="text" name="skinUrl" id="skin-url" placeholder="Leave blank to keep">
</p> </p>
<p> <p>
<label for="skinFile">or instead, upload a skin</label><br> <label for="skin-file">or instead, upload a skin</label><br>
<input type="file" name="skinFile" id="skin-file"> <input type="file" name="skinFile" id="skin-file">
</p> </p>
<p>
<label for="delete-skin">or instead, check the box to delete your current skin </label>
<input type="checkbox" name="deleteSkin" id="delete-skin">
</p>
<p> <p>
<fieldset> <fieldset>
<legend>Skin model</legend> <legend>Skin model</legend>
@ -100,6 +104,10 @@
<label for="capeFile">or instead, upload a cape</label><br> <label for="capeFile">or instead, upload a cape</label><br>
<input type="file" name="capeFile" id="cape-file"> <input type="file" name="capeFile" id="cape-file">
</p> </p>
<p>
<label for="delete-cape">or instead, check the box to delete your current cape </label>
<input type="checkbox" name="deleteCape" id="delete-cape">
</p>
<input type="submit" value="Save Changes"> <input type="submit" value="Save Changes">
</form> </form>
<p> <p>