获取皮肤接口
This commit is contained in:
parent
7ed8f72640
commit
fc727c87a3
@ -15,8 +15,9 @@ type Config struct {
|
||||
Type string
|
||||
Ram int
|
||||
}
|
||||
RaelIP bool
|
||||
MaxIpUser int
|
||||
RsaPriKey string
|
||||
TexturePath string
|
||||
RaelIP bool
|
||||
MaxIpUser int
|
||||
RsaPriKey string
|
||||
TexturePath string
|
||||
TextureBaseUrl string
|
||||
}
|
||||
|
@ -36,5 +36,7 @@ func (UserProfile) Edges() []ent.Edge {
|
||||
func (UserProfile) Indexes() []ent.Index {
|
||||
return []ent.Index{
|
||||
index.Edges("user"),
|
||||
index.Fields("name"),
|
||||
index.Fields("uuid"),
|
||||
}
|
||||
}
|
||||
|
@ -18,11 +18,11 @@ func (UserTexture) Fields() []ent.Field {
|
||||
return []ent.Field{
|
||||
field.Int("user_profile_id"),
|
||||
field.Int("texture_id"),
|
||||
// 皮肤 or 披风
|
||||
// skin or cape
|
||||
field.String("type").SchemaType(map[string]string{
|
||||
dialect.MySQL: "VARCHAR(10)",
|
||||
}),
|
||||
// slim or 空
|
||||
// slim or ""
|
||||
field.String("variant").SchemaType(map[string]string{
|
||||
dialect.MySQL: "VARCHAR(10)",
|
||||
}),
|
||||
|
@ -119,3 +119,37 @@ func (y *Yggdrasil) Refresh() httprouter.Handle {
|
||||
w.Write(b)
|
||||
}
|
||||
}
|
||||
|
||||
func (y *Yggdrasil) GetProfile() httprouter.Handle {
|
||||
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
||||
ctx := r.Context()
|
||||
uuid := p.ByName("uuid")
|
||||
unsigned := r.FormValue("unsigned")
|
||||
|
||||
unsignedBool := true
|
||||
|
||||
switch unsigned {
|
||||
case "true":
|
||||
case "false":
|
||||
unsignedBool = false
|
||||
default:
|
||||
y.logger.DebugContext(ctx, "unsigned 参数类型错误")
|
||||
handleYgError(ctx, w, yggdrasil.Error{ErrorMessage: "unsigned 参数类型错误"}, 400)
|
||||
return
|
||||
|
||||
}
|
||||
u, err := y.yggdrasilService.GetProfile(ctx, uuid, unsignedBool, r.Host)
|
||||
if err != nil {
|
||||
if errors.Is(err, yggdrasilS.ErrNotUser) {
|
||||
y.logger.DebugContext(ctx, err.Error())
|
||||
w.WriteHeader(204)
|
||||
return
|
||||
}
|
||||
y.logger.WarnContext(ctx, err.Error())
|
||||
handleYgError(ctx, w, yggdrasil.Error{ErrorMessage: err.Error()}, 500)
|
||||
return
|
||||
}
|
||||
b, _ := json.Marshal(u)
|
||||
w.Write(b)
|
||||
}
|
||||
}
|
||||
|
@ -52,3 +52,15 @@ type RefreshToken struct {
|
||||
RequestUser bool `json:"requestUser"`
|
||||
SelectedProfile TokenProfile `json:"selectedProfile"`
|
||||
}
|
||||
|
||||
type UserInfo struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Properties []UserProperties `json:"properties"`
|
||||
}
|
||||
|
||||
type UserProperties struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
Signature string `json:"signature,omitempty"`
|
||||
}
|
||||
|
28
model/yggdrasil/textures.go
Normal file
28
model/yggdrasil/textures.go
Normal file
@ -0,0 +1,28 @@
|
||||
package yggdrasil
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
type UserTextures struct {
|
||||
// UUID
|
||||
ProfileID string `json:"profileId"`
|
||||
ProfileName string `json:"profileName"`
|
||||
Textures map[string]Textures `json:"textures"`
|
||||
// 时间戳 毫秒
|
||||
Timestamp string `json:"timestamp"`
|
||||
}
|
||||
|
||||
type Textures struct {
|
||||
Url string `json:"url"`
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
}
|
||||
|
||||
func (u UserTextures) Base64() string {
|
||||
b, err := json.Marshal(u)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(b)
|
||||
}
|
@ -27,9 +27,13 @@ func newYggdrasil(r *httprouter.Router, handelY yggdrasil.Yggdrasil) error {
|
||||
r.POST("/api/yggdrasil/authserver/validate", warpHJSON(handelY.Validate()))
|
||||
r.POST("/api/yggdrasil/authserver/signout", warpHJSON(handelY.Signout()))
|
||||
r.POST("/api/yggdrasil/authserver/invalidate", handelY.Invalidate())
|
||||
r.POST("/api/yggdrasil/authserver/refresh", handelY.Refresh())
|
||||
r.POST("/api/yggdrasil/authserver/refresh", warpHJSON(handelY.Refresh()))
|
||||
|
||||
r.PUT("/api/yggdrasil/api/user/profile/:uuid/:textureType", handelY.PutTexture())
|
||||
r.DELETE("/api/yggdrasil/api/user/profile/:uuid/:textureType", handelY.DelTexture())
|
||||
r.DELETE("/api/yggdrasil/api/user/profile/:uuid/:textureType", warpHJSON(handelY.DelTexture()))
|
||||
|
||||
r.GET("/sessionserver/session/minecraft/profile/:uuid", handelY.GetProfile())
|
||||
|
||||
r.GET("/api/yggdrasil", func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
||||
w.Write([]byte(`{
|
||||
"meta": {
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@ -16,11 +17,13 @@ import (
|
||||
"github.com/xmdhs/authlib-skin/model/yggdrasil"
|
||||
sutils "github.com/xmdhs/authlib-skin/service/utils"
|
||||
"github.com/xmdhs/authlib-skin/utils"
|
||||
"github.com/xmdhs/authlib-skin/utils/sign"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrRate = errors.New("频率限制")
|
||||
ErrPassWord = errors.New("错误的密码或邮箱")
|
||||
ErrNotUser = errors.New("没有这个用户")
|
||||
)
|
||||
|
||||
func (y *Yggdrasil) validatePass(cxt context.Context, email, pass string) (*ent.User, error) {
|
||||
@ -164,3 +167,62 @@ func (y *Yggdrasil) Refresh(ctx context.Context, token yggdrasil.RefreshToken) (
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (y *Yggdrasil) GetProfile(ctx context.Context, uuid string, unsigned bool, host string) (yggdrasil.UserInfo, error) {
|
||||
up, err := y.client.UserProfile.Query().Where(userprofile.UUID(uuid)).WithUsertexture().WithTexture().Only(ctx)
|
||||
if err != nil {
|
||||
var nf *ent.NotFoundError
|
||||
if errors.As(err, &nf) {
|
||||
return yggdrasil.UserInfo{}, fmt.Errorf("GetProfile: %w", ErrNotUser)
|
||||
}
|
||||
return yggdrasil.UserInfo{}, fmt.Errorf("GetProfile: %w", err)
|
||||
}
|
||||
var baseURl string
|
||||
if y.config.TextureBaseUrl == "" {
|
||||
baseURl = path.Join(host, "textures")
|
||||
}
|
||||
|
||||
ut := yggdrasil.UserTextures{
|
||||
ProfileID: up.UUID,
|
||||
ProfileName: up.Name,
|
||||
Textures: map[string]yggdrasil.Textures{},
|
||||
Timestamp: strconv.FormatInt(time.Now().UnixMilli(), 10),
|
||||
}
|
||||
|
||||
for _, v := range up.Edges.Usertexture {
|
||||
hashstr := v.Edges.Texture.TextureHash
|
||||
t := yggdrasil.Textures{
|
||||
Url: path.Join(baseURl, hashstr[:2], hashstr[2:4], hashstr),
|
||||
Metadata: map[string]string{},
|
||||
}
|
||||
if v.Variant == "slim" {
|
||||
t.Metadata["model"] = "slim"
|
||||
}
|
||||
ut.Textures[strings.ToTitle(v.Type)] = t
|
||||
}
|
||||
|
||||
texturesBase64 := ut.Base64()
|
||||
|
||||
var signStr string
|
||||
if !unsigned {
|
||||
s := sign.NewAuthlibSignWithKey(y.prikey)
|
||||
signStr, err = s.Sign([]byte(texturesBase64))
|
||||
if err != nil {
|
||||
return yggdrasil.UserInfo{}, fmt.Errorf("GetProfile: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
uinfo := yggdrasil.UserInfo{
|
||||
ID: up.UUID,
|
||||
Name: up.Name,
|
||||
Properties: []yggdrasil.UserProperties{
|
||||
{
|
||||
Name: "textures",
|
||||
Value: texturesBase64,
|
||||
Signature: signStr,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return uinfo, nil
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user