package main import ( "bytes" "errors" "image" _ "image/png" "net/http" "os" "strings" "github.com/gorilla/mux" ) func logInEndpoint(w http.ResponseWriter, r *http.Request) { var details UserCredentials err := unmarshalTo(r, &details) if err != nil { handleError(w, err) return } invalidCreds := YggError{ Code: 401, Error: "Unauthorized", ErrorMessage: "Invalid credentials.", } exists, err := playerExistsByUsername(details.Username) if err != nil { handleError(w, err) return } if !exists { sendError(w, invalidCreds) return } correct, err := checkPlayerPassByUsername(details.Username, details.Password) if err != nil { handleError(w, err) return } if correct { response := WebLogInResponse{} webToken, err := getWebToken(details.Username, details.Password) if err != nil { handleError(w, err) return } player, err := getPlayerByUsername(details.Username) if err != nil { handleError(w, err) return } response.Token = webToken response.UUID = player.UUID response.Username = player.Username sendJSON(w, response) } else { sendError(w, YggError{ Code: 401, Error: "Unauthorized", ErrorMessage: "Invalid credentials.", }) } } func getTextureEndpoint(w http.ResponseWriter, r *http.Request) { uuid := mux.Vars(r)["uuid"] query := r.URL.Query() if !query.Has("type") { sendError(w, YggError{ Code: 400, Error: "Bad Request", ErrorMessage: "Must specify texture type. Add ?type=skin or ?type=cape to the URL.", }) return } textureId := query.Get("type") if !(textureId == "skin" || textureId == "cape") { sendError(w, YggError{ Code: 400, Error: "Bad Request", ErrorMessage: "Invalid texture type.", }) return } skin, err := getPlayerTexture(textureId, uuid) if err != nil { if !errors.Is(err, &NotFoundError{}) { handleError(w, err) return } skin, err = os.ReadFile("default.png") if err != nil { handleError(w, err) return } } w.Header().Set("Content-Type", "image/png") w.Write(skin) } func setTextureEndpoint(w http.ResponseWriter, r *http.Request) { uuid := mux.Vars(r)["uuid"] query := r.URL.Query() if !query.Has("type") { sendError(w, YggError{Code: 400, Error: "Bad Request", ErrorMessage: "Must specify texture type. Add ?type=skin or ?type=cape to the URL."}) return } textureId := query.Get("type") if !(textureId == "skin" || textureId == "cape") { sendError(w, YggError{ Code: 400, Error: "Bad Request", ErrorMessage: "Invalid texture type.", }) return } if len(uuid) == 32 { uuid = growUUID(uuid) } if len(uuid) != 36 { sendError(w, YggError{ Code: 400, Error: "Bad Request", ErrorMessage: "Invalid UUID.", }) return } r.ParseMultipartForm(int64(config.MaxTextureSize)) token := r.FormValue("token") player, err := getPlayerByUUID(uuid) if err != nil { handleError(w, err) return } if token != player.WebToken { sendError(w, YggError{Code: 400, Error: "Bad Request", ErrorMessage: "Invalid credentials."}) return } file, _, err := recievePNG("file", w, r) if err != nil { handleError(w, err) return } reader := bytes.NewReader(file) img, _, err := image.Decode(reader) if err != nil { sendError(w, YggError{ Code: 400, Error: "Bad Request", ErrorMessage: "The request data is malformed.", }) return } bounds := img.Bounds() targetX := 64 targetY := 64 if textureId == "cape" { targetY = 32 } if bounds.Dx() != targetX || bounds.Dy() != targetY { sendError(w, YggError{ Code: 400, Error: "Bad Request", ErrorMessage: "The request data is malformed.", }) return } err = setPlayerTexture(textureId, uuid, file) if err != nil { handleError(w, err) return } sendEmpty(w) } func rootRedirect(w http.ResponseWriter, r *http.Request) { if strings.HasPrefix(r.Header.Get("User-Agent"), "Java") { rootEndpoint(w, r) return } http.Redirect(w, r, "/web", http.StatusMovedPermanently) } func registerWebEndpoints(r *mux.Router) { webDir := "/web" r.HandleFunc("/", rootRedirect) r.HandleFunc("/webapi/logIn", logInEndpoint).Methods("POST") r.PathPrefix(webDir). Handler(http.StripPrefix(webDir, http.FileServer(http.Dir("."+webDir)))) r.HandleFunc("/getTexture/{uuid}", getTextureEndpoint).Methods("GET") r.HandleFunc("/setTexture/{uuid}", setTextureEndpoint).Methods("POST") }