2023-09-09 00:26:52 +08:00

155 lines
3.9 KiB
Go

package yggdrasil
import (
"bytes"
"context"
"errors"
"fmt"
"image/png"
"io"
"log/slog"
"net/http"
"strings"
"github.com/julienschmidt/httprouter"
"github.com/xmdhs/authlib-skin/model/yggdrasil"
"github.com/xmdhs/authlib-skin/service/utils"
)
func (y *Yggdrasil) getTokenbyAuthorization(ctx context.Context, w http.ResponseWriter, r *http.Request) string {
auth := r.Header.Get("Authorization")
if auth == "" {
y.logger.DebugContext(ctx, "缺少 Authorization")
w.WriteHeader(401)
return ""
}
al := strings.Split(auth, " ")
if len(al) != 2 || al[0] != "Bearer" {
y.logger.DebugContext(ctx, "Authorization 格式错误")
w.WriteHeader(401)
return ""
}
return al[1]
}
func (y *Yggdrasil) validTextureType(ctx context.Context, w http.ResponseWriter, textureType string) bool {
switch textureType {
case "skin":
case "cape":
default:
y.logger.DebugContext(ctx, "错误的材质类型")
handleYgError(ctx, w, yggdrasil.Error{ErrorMessage: "错误的材质类型"}, 400)
return false
}
return true
}
func (y *Yggdrasil) PutTexture() httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
ctx := r.Context()
uuid, textureType, ok := getUUIDbyParams(ctx, p, y.logger, w)
if !ok {
return
}
token := y.getTokenbyAuthorization(ctx, w, r)
if token == "" {
return
}
model := r.FormValue("model")
skin, err := func() ([]byte, error) {
f, _, err := r.FormFile("file")
if err != nil {
return nil, err
}
b, err := io.ReadAll(io.LimitReader(f, 50*1000))
if err != nil {
return nil, err
}
pc, err := png.DecodeConfig(bytes.NewReader(b))
if err != nil {
return nil, err
}
if pc.Height > 200 || pc.Width > 200 {
return nil, fmt.Errorf("材质大小超过限制")
}
p, err := png.Decode(bytes.NewReader(b))
if err != nil {
return nil, err
}
bw := bytes.NewBuffer(nil)
err = png.Encode(bw, p)
return bw.Bytes(), err
}()
if err != nil {
y.logger.DebugContext(ctx, err.Error())
handleYgError(ctx, w, yggdrasil.Error{ErrorMessage: err.Error()}, 400)
return
}
if !y.validTextureType(ctx, w, textureType) {
return
}
switch model {
case "slim":
case "":
default:
y.logger.DebugContext(ctx, "错误的皮肤的材质模型")
handleYgError(ctx, w, yggdrasil.Error{ErrorMessage: "错误的皮肤的材质模型"}, 400)
return
}
err = y.yggdrasilService.PutTexture(ctx, token, skin, model, uuid, textureType)
if err != nil {
if errors.Is(err, utils.ErrTokenInvalid) {
y.logger.DebugContext(ctx, err.Error())
w.WriteHeader(401)
return
}
y.logger.WarnContext(ctx, err.Error())
handleYgError(ctx, w, yggdrasil.Error{ErrorMessage: err.Error()}, 500)
return
}
w.WriteHeader(204)
}
}
func getUUIDbyParams(ctx context.Context, p httprouter.Params, l *slog.Logger, w http.ResponseWriter) (string, string, bool) {
uuid := p.ByName("uuid")
textureType := p.ByName("textureType")
if uuid == "" || textureType == "" {
l.DebugContext(ctx, "路径中缺少参数 uuid / textureType")
handleYgError(ctx, w, yggdrasil.Error{ErrorMessage: "路径中缺少参数 uuid / textureType"}, 400)
return "", "", false
}
return uuid, textureType, true
}
func (y *Yggdrasil) DelTexture() httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
ctx := r.Context()
uuid, textureType, ok := getUUIDbyParams(ctx, p, y.logger, w)
if !ok {
return
}
token := y.getTokenbyAuthorization(ctx, w, r)
if token == "" {
return
}
err := y.yggdrasilService.DelTexture(ctx, uuid, token, textureType)
if err != nil {
if errors.Is(err, utils.ErrTokenInvalid) {
y.logger.DebugContext(ctx, err.Error())
w.WriteHeader(401)
return
}
y.logger.WarnContext(ctx, err.Error())
handleYgError(ctx, w, yggdrasil.Error{ErrorMessage: err.Error()}, 500)
return
}
w.WriteHeader(204)
}
}