This commit is contained in:
xmdhs 2023-09-10 21:50:30 +08:00
parent bfaf686ff0
commit f6a914fd85
No known key found for this signature in database
GPG Key ID: E809D6D43DEFCC95
6 changed files with 132 additions and 2 deletions

View File

@ -0,0 +1,54 @@
package yggdrasil
import (
"errors"
"net/http"
"github.com/julienschmidt/httprouter"
"github.com/xmdhs/authlib-skin/model/yggdrasil"
sutils "github.com/xmdhs/authlib-skin/service/utils"
"github.com/xmdhs/authlib-skin/utils"
)
func (y *Yggdrasil) SessionJoin() httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
ctx := r.Context()
a, has := getAnyModel[yggdrasil.Session](ctx, w, r.Body, y.validate, y.logger)
if !has {
return
}
ip, err := utils.GetIP(r, y.config.RaelIP)
if err != nil {
y.logger.WarnContext(ctx, err.Error())
handleYgError(ctx, w, yggdrasil.Error{ErrorMessage: err.Error()}, 500)
return
}
err = y.yggdrasilService.SessionJoin(ctx, a, ip)
if err != nil {
if errors.Is(err, sutils.ErrTokenInvalid) {
y.logger.DebugContext(ctx, err.Error())
handleYgError(ctx, w, yggdrasil.Error{ErrorMessage: "Invalid token.", Error: "ForbiddenOperationException"}, 403)
return
}
y.logger.WarnContext(ctx, err.Error())
handleYgError(ctx, w, yggdrasil.Error{ErrorMessage: err.Error()}, 500)
return
}
w.WriteHeader(204)
}
}
func (y *Yggdrasil) HasJoined() httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
ctx := r.Context()
name := r.FormValue("username")
serverId := r.FormValue("serverId")
ip := r.FormValue("ip")
if name == "" || serverId == "" {
y.logger.DebugContext(ctx, "name 或 serverID 为空")
w.WriteHeader(204)
return
}
y.yggdrasilService.HasJoined(ctx, name, serverId, ip, r.Host)
}
}

View File

@ -7,6 +7,7 @@ import (
"net/http" "net/http"
"github.com/go-playground/validator/v10" "github.com/go-playground/validator/v10"
"github.com/xmdhs/authlib-skin/config"
"github.com/xmdhs/authlib-skin/model/yggdrasil" "github.com/xmdhs/authlib-skin/model/yggdrasil"
yggdrasilS "github.com/xmdhs/authlib-skin/service/yggdrasil" yggdrasilS "github.com/xmdhs/authlib-skin/service/yggdrasil"
"github.com/xmdhs/authlib-skin/utils" "github.com/xmdhs/authlib-skin/utils"
@ -16,13 +17,15 @@ type Yggdrasil struct {
logger *slog.Logger logger *slog.Logger
validate *validator.Validate validate *validator.Validate
yggdrasilService *yggdrasilS.Yggdrasil yggdrasilService *yggdrasilS.Yggdrasil
config config.Config
} }
func NewYggdrasil(logger *slog.Logger, validate *validator.Validate, yggdrasilService *yggdrasilS.Yggdrasil) *Yggdrasil { func NewYggdrasil(logger *slog.Logger, validate *validator.Validate, yggdrasilService *yggdrasilS.Yggdrasil, config config.Config) *Yggdrasil {
return &Yggdrasil{ return &Yggdrasil{
logger: logger, logger: logger,
validate: validate, validate: validate,
yggdrasilService: yggdrasilService, yggdrasilService: yggdrasilService,
config: config,
} }
} }

View File

@ -57,3 +57,9 @@ type UserProperties struct {
Value string `json:"value"` Value string `json:"value"`
Signature string `json:"signature,omitempty"` Signature string `json:"signature,omitempty"`
} }
type Session struct {
AccessToken string `json:"accessToken" validate:"required,jwt"`
SelectedProfile string `json:"selectedProfile" validate:"required,uuid"`
ServerID string `json:"serverId"`
}

View File

@ -35,6 +35,9 @@ func newYggdrasil(r *httprouter.Router, handelY yggdrasil.Yggdrasil) error {
r.GET("/api/yggdrasil/sessionserver/session/minecraft/profile/:uuid", warpHJSON(handelY.GetProfile())) r.GET("/api/yggdrasil/sessionserver/session/minecraft/profile/:uuid", warpHJSON(handelY.GetProfile()))
r.POST("/api/yggdrasil/api/profiles/minecraft", warpHJSON(handelY.BatchProfile())) r.POST("/api/yggdrasil/api/profiles/minecraft", warpHJSON(handelY.BatchProfile()))
r.POST("/api/yggdrasil/sessionserver/session/minecraft/join", warpHJSON(handelY.SessionJoin()))
r.GET("/api/yggdrasil/sessionserver/session/minecraft/hasJoined", warpHJSON(handelY.SessionJoin()))
r.GET("/api/yggdrasil", func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { r.GET("/api/yggdrasil", func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
w.Write([]byte(`{ w.Write([]byte(`{
"meta": { "meta": {

View File

@ -44,7 +44,7 @@ func InitializeRoute(ctx context.Context, c config.Config) (*http.Server, func()
return nil, nil, err return nil, nil, err
} }
yggdrasilYggdrasil := yggdrasil.NewYggdrasil(client, cache, c, privateKey) yggdrasilYggdrasil := yggdrasil.NewYggdrasil(client, cache, c, privateKey)
yggdrasil3 := yggdrasil2.NewYggdrasil(logger, validate, yggdrasilYggdrasil) yggdrasil3 := yggdrasil2.NewYggdrasil(logger, validate, yggdrasilYggdrasil, c)
webService := service.NewWebService(c, client) webService := service.NewWebService(c, client)
handel := handle.NewHandel(webService, validate, c, logger) handel := handle.NewHandel(webService, validate, c, logger)
router, err := route.NewRoute(yggdrasil3, handel) router, err := route.NewRoute(yggdrasil3, handel)

View File

@ -0,0 +1,64 @@
package yggdrasil
import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/samber/lo"
"github.com/xmdhs/authlib-skin/db/ent/userprofile"
"github.com/xmdhs/authlib-skin/model"
"github.com/xmdhs/authlib-skin/model/yggdrasil"
sutils "github.com/xmdhs/authlib-skin/service/utils"
)
type sessionWithIP struct {
user model.TokenClaims
IP string
}
func (y *Yggdrasil) SessionJoin(ctx context.Context, s yggdrasil.Session, ip string) error {
t, err := sutils.Auth(ctx, yggdrasil.ValidateToken{
AccessToken: s.AccessToken,
}, y.client, &y.prikey.PublicKey, true)
if err != nil {
return fmt.Errorf("SessionJoin: %w", err)
}
if s.SelectedProfile != t.Subject {
return fmt.Errorf("SessionJoin: %w", sutils.ErrTokenInvalid)
}
err = y.cache.Put([]byte("session"+s.ServerID), lo.Must1(json.Marshal(sessionWithIP{
user: *t,
IP: ip,
})), time.Now().Add(30*time.Second))
if err != nil {
return fmt.Errorf("SessionJoin: %w", err)
}
return nil
}
func (y *Yggdrasil) HasJoined(ctx context.Context, username, serverId string, ip string, host string) (yggdrasil.UserInfo, error) {
b := lo.Must1(y.cache.Get([]byte("session" + serverId)))
sIP := sessionWithIP{}
lo.Must0(json.Unmarshal(b, &sIP))
if ip != "" && ip != sIP.IP {
return yggdrasil.UserInfo{}, fmt.Errorf("ip 不相同")
}
up, err := y.client.UserProfile.Query().Where(userprofile.Name(username)).Only(ctx)
if err != nil {
return yggdrasil.UserInfo{}, fmt.Errorf("HasJoined: %w", err)
}
if up.UUID != sIP.user.Subject {
return yggdrasil.UserInfo{}, fmt.Errorf("uuid 不相同")
}
u, err := y.GetProfile(ctx, up.UUID, false, host)
if err != nil {
return yggdrasil.UserInfo{}, fmt.Errorf("HasJoined: %w", err)
}
return u, nil
}