tripwire/web.go

215 lines
4.4 KiB
Go

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")
}