改成 go-chi/chi

This commit is contained in:
xmdhs 2023-10-08 00:05:36 +08:00
parent a64ab9e838
commit b011910d20
No known key found for this signature in database
GPG Key ID: E809D6D43DEFCC95
20 changed files with 219 additions and 221 deletions

4
go.mod
View File

@ -6,12 +6,13 @@ require (
entgo.io/ent v0.12.3 entgo.io/ent v0.12.3
github.com/VictoriaMetrics/fastcache v1.12.1 github.com/VictoriaMetrics/fastcache v1.12.1
github.com/alecthomas/binary v0.0.0-20221018225505-74871811ee56 github.com/alecthomas/binary v0.0.0-20221018225505-74871811ee56
github.com/go-chi/chi/v5 v5.0.10
github.com/go-chi/cors v1.2.1
github.com/go-playground/validator/v10 v10.15.3 github.com/go-playground/validator/v10 v10.15.3
github.com/go-sql-driver/mysql v1.7.1 github.com/go-sql-driver/mysql v1.7.1
github.com/golang-jwt/jwt/v5 v5.0.0 github.com/golang-jwt/jwt/v5 v5.0.0
github.com/google/uuid v1.3.1 github.com/google/uuid v1.3.1
github.com/google/wire v0.5.0 github.com/google/wire v0.5.0
github.com/julienschmidt/httprouter v1.3.0
github.com/samber/lo v1.38.1 github.com/samber/lo v1.38.1
golang.org/x/crypto v0.7.0 golang.org/x/crypto v0.7.0
) )
@ -22,6 +23,7 @@ require (
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/go-chi/chi v1.5.5
github.com/go-openapi/inflect v0.19.0 // indirect github.com/go-openapi/inflect v0.19.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect

8
go.sum
View File

@ -21,6 +21,12 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/go-chi/chi v1.5.5 h1:vOB/HbEMt9QqBqErz07QehcOKHaWFtuj87tTDVz2qXE=
github.com/go-chi/chi v1.5.5/go.mod h1:C9JqLr3tIYjDOZpzn+BCuxY8z8vmca43EeMgyZt7irw=
github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4= github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4=
github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4= github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
@ -52,8 +58,6 @@ github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8=
github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU=
github.com/hashicorp/hcl/v2 v2.13.0 h1:0Apadu1w6M11dyGFxWnmhhcMjkbAiKCv7G1r/2QgCNc= github.com/hashicorp/hcl/v2 v2.13.0 h1:0Apadu1w6M11dyGFxWnmhhcMjkbAiKCv7G1r/2QgCNc=
github.com/hashicorp/hcl/v2 v2.13.0/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0zIUqPc2jr0= github.com/hashicorp/hcl/v2 v2.13.0/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0zIUqPc2jr0=
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=

View File

@ -6,13 +6,12 @@ import (
"net/http" "net/http"
"strconv" "strconv"
"github.com/julienschmidt/httprouter"
"github.com/xmdhs/authlib-skin/model" "github.com/xmdhs/authlib-skin/model"
utilsService "github.com/xmdhs/authlib-skin/service/utils" utilsService "github.com/xmdhs/authlib-skin/service/utils"
) )
func (h *Handel) NeedAdmin(handle httprouter.Handle) httprouter.Handle { func (h *Handel) NeedAdmin(handle http.Handler) http.Handler {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
token := h.getTokenbyAuthorization(ctx, w, r) token := h.getTokenbyAuthorization(ctx, w, r)
if token == "" { if token == "" {
@ -27,12 +26,12 @@ func (h *Handel) NeedAdmin(handle httprouter.Handle) httprouter.Handle {
h.handleError(ctx, w, err.Error(), model.ErrService, 500, slog.LevelWarn) h.handleError(ctx, w, err.Error(), model.ErrService, 500, slog.LevelWarn)
return return
} }
handle(w, r, p) handle.ServeHTTP(w, r)
} })
} }
func (h *Handel) ListUser() httprouter.Handle { func (h *Handel) ListUser() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
page := r.FormValue("page") page := r.FormValue("page")
pagei := 1 pagei := 1

View File

@ -4,12 +4,11 @@ import (
"encoding/json" "encoding/json"
"net/http" "net/http"
"github.com/julienschmidt/httprouter"
"github.com/xmdhs/authlib-skin/model" "github.com/xmdhs/authlib-skin/model"
) )
func (h *Handel) GetConfig() httprouter.Handle { func (h *Handel) GetConfig() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
c := h.webService.GetConfig(ctx) c := h.webService.GetConfig(ctx)
m := model.API[model.Config]{ m := model.API[model.Config]{

View File

@ -5,18 +5,17 @@ import (
"log/slog" "log/slog"
"net/http" "net/http"
"github.com/julienschmidt/httprouter"
"github.com/xmdhs/authlib-skin/model" "github.com/xmdhs/authlib-skin/model"
"github.com/xmdhs/authlib-skin/service" "github.com/xmdhs/authlib-skin/service"
utilsService "github.com/xmdhs/authlib-skin/service/utils" utilsService "github.com/xmdhs/authlib-skin/service/utils"
"github.com/xmdhs/authlib-skin/utils" "github.com/xmdhs/authlib-skin/utils"
) )
func (h *Handel) Reg() httprouter.Handle { func (h *Handel) Reg() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
ip, err := utils.GetIP(r, h.config.RaelIP) ip, err := utils.GetIP(r)
if err != nil { if err != nil {
h.handleError(ctx, w, err.Error(), model.ErrInput, 400, slog.LevelDebug) h.handleError(ctx, w, err.Error(), model.ErrInput, 400, slog.LevelDebug)
return return
@ -55,8 +54,8 @@ func (h *Handel) Reg() httprouter.Handle {
} }
} }
func (h *Handel) UserInfo() httprouter.Handle { func (h *Handel) UserInfo() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
token := h.getTokenbyAuthorization(ctx, w, r) token := h.getTokenbyAuthorization(ctx, w, r)
if token == "" { if token == "" {
@ -79,8 +78,8 @@ func (h *Handel) UserInfo() httprouter.Handle {
} }
} }
func (h *Handel) ChangePasswd() httprouter.Handle { func (h *Handel) ChangePasswd() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
token := h.getTokenbyAuthorization(ctx, w, r) token := h.getTokenbyAuthorization(ctx, w, r)
if token == "" { if token == "" {
@ -108,8 +107,8 @@ func (h *Handel) ChangePasswd() httprouter.Handle {
} }
} }
func (h *Handel) ChangeName() httprouter.Handle { func (h *Handel) ChangeName() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
token := h.getTokenbyAuthorization(ctx, w, r) token := h.getTokenbyAuthorization(ctx, w, r)
if token == "" { if token == "" {

View File

@ -20,5 +20,4 @@ func handleYgError(ctx context.Context, w http.ResponseWriter, e yggdrasil.Error
func (y *Yggdrasil) handleYgError(ctx context.Context, w http.ResponseWriter, err error) { func (y *Yggdrasil) handleYgError(ctx context.Context, w http.ResponseWriter, err error) {
y.logger.WarnContext(ctx, err.Error()) y.logger.WarnContext(ctx, err.Error())
handleYgError(ctx, w, yggdrasil.Error{ErrorMessage: err.Error()}, 500) handleYgError(ctx, w, yggdrasil.Error{ErrorMessage: err.Error()}, 500)
return
} }

View File

@ -5,21 +5,20 @@ import (
"errors" "errors"
"net/http" "net/http"
"github.com/julienschmidt/httprouter"
"github.com/samber/lo" "github.com/samber/lo"
"github.com/xmdhs/authlib-skin/model/yggdrasil" "github.com/xmdhs/authlib-skin/model/yggdrasil"
sutils "github.com/xmdhs/authlib-skin/service/utils" sutils "github.com/xmdhs/authlib-skin/service/utils"
"github.com/xmdhs/authlib-skin/utils" "github.com/xmdhs/authlib-skin/utils"
) )
func (y *Yggdrasil) SessionJoin() httprouter.Handle { func (y *Yggdrasil) SessionJoin() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
a, has := getAnyModel[yggdrasil.Session](ctx, w, r.Body, y.validate, y.logger) a, has := getAnyModel[yggdrasil.Session](ctx, w, r.Body, y.validate, y.logger)
if !has { if !has {
return return
} }
ip, err := utils.GetIP(r, y.config.RaelIP) ip, err := utils.GetIP(r)
if err != nil { if err != nil {
y.handleYgError(ctx, w, err) y.handleYgError(ctx, w, err)
return return
@ -38,8 +37,8 @@ func (y *Yggdrasil) SessionJoin() httprouter.Handle {
} }
} }
func (y *Yggdrasil) HasJoined() httprouter.Handle { func (y *Yggdrasil) HasJoined() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
name := r.FormValue("username") name := r.FormValue("username")
serverId := r.FormValue("serverId") serverId := r.FormValue("serverId")

View File

@ -11,7 +11,7 @@ import (
"net/http" "net/http"
"strings" "strings"
"github.com/julienschmidt/httprouter" "github.com/go-chi/chi/v5"
"github.com/xmdhs/authlib-skin/model/yggdrasil" "github.com/xmdhs/authlib-skin/model/yggdrasil"
"github.com/xmdhs/authlib-skin/service/utils" "github.com/xmdhs/authlib-skin/service/utils"
) )
@ -44,10 +44,10 @@ func (y *Yggdrasil) validTextureType(ctx context.Context, w http.ResponseWriter,
return true return true
} }
func (y *Yggdrasil) PutTexture() httprouter.Handle { func (y *Yggdrasil) PutTexture() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
uuid, textureType, ok := getUUIDbyParams(ctx, p, y.logger, w) uuid, textureType, ok := getUUIDbyParams(ctx, y.logger, w)
if !ok { if !ok {
return return
} }
@ -115,9 +115,9 @@ func (y *Yggdrasil) PutTexture() httprouter.Handle {
} }
} }
func getUUIDbyParams(ctx context.Context, p httprouter.Params, l *slog.Logger, w http.ResponseWriter) (string, string, bool) { func getUUIDbyParams(ctx context.Context, l *slog.Logger, w http.ResponseWriter) (string, string, bool) {
uuid := p.ByName("uuid") uuid := chi.URLParamFromCtx(ctx, "uuid")
textureType := p.ByName("textureType") textureType := chi.URLParamFromCtx(ctx, "textureType")
if uuid == "" { if uuid == "" {
l.DebugContext(ctx, "路径中缺少参数 uuid") l.DebugContext(ctx, "路径中缺少参数 uuid")
handleYgError(ctx, w, yggdrasil.Error{ErrorMessage: "路径中缺少参数 uuid / textureType"}, 400) handleYgError(ctx, w, yggdrasil.Error{ErrorMessage: "路径中缺少参数 uuid / textureType"}, 400)
@ -132,10 +132,10 @@ func getUUIDbyParams(ctx context.Context, p httprouter.Params, l *slog.Logger, w
return uuid, textureType, true return uuid, textureType, true
} }
func (y *Yggdrasil) DelTexture() httprouter.Handle { func (y *Yggdrasil) DelTexture() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
uuid, textureType, ok := getUUIDbyParams(ctx, p, y.logger, w) uuid, textureType, ok := getUUIDbyParams(ctx, y.logger, w)
if !ok { if !ok {
return return
} }

View File

@ -5,15 +5,15 @@ import (
"errors" "errors"
"net/http" "net/http"
"github.com/julienschmidt/httprouter" "github.com/go-chi/chi/v5"
"github.com/samber/lo" "github.com/samber/lo"
"github.com/xmdhs/authlib-skin/model/yggdrasil" "github.com/xmdhs/authlib-skin/model/yggdrasil"
sutils "github.com/xmdhs/authlib-skin/service/utils" sutils "github.com/xmdhs/authlib-skin/service/utils"
yggdrasilS "github.com/xmdhs/authlib-skin/service/yggdrasil" yggdrasilS "github.com/xmdhs/authlib-skin/service/yggdrasil"
) )
func (y *Yggdrasil) Authenticate() httprouter.Handle { func (y *Yggdrasil) Authenticate() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { return func(w http.ResponseWriter, r *http.Request) {
cxt := r.Context() cxt := r.Context()
a, has := getAnyModel[yggdrasil.Authenticate](cxt, w, r.Body, y.validate, y.logger) a, has := getAnyModel[yggdrasil.Authenticate](cxt, w, r.Body, y.validate, y.logger)
if !has { if !has {
@ -34,8 +34,8 @@ func (y *Yggdrasil) Authenticate() httprouter.Handle {
} }
} }
func (y *Yggdrasil) Validate() httprouter.Handle { func (y *Yggdrasil) Validate() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { return func(w http.ResponseWriter, r *http.Request) {
cxt := r.Context() cxt := r.Context()
a, has := getAnyModel[yggdrasil.ValidateToken](cxt, w, r.Body, y.validate, y.logger) a, has := getAnyModel[yggdrasil.ValidateToken](cxt, w, r.Body, y.validate, y.logger)
if !has { if !has {
@ -55,8 +55,8 @@ func (y *Yggdrasil) Validate() httprouter.Handle {
} }
} }
func (y *Yggdrasil) Signout() httprouter.Handle { func (y *Yggdrasil) Signout() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { return func(w http.ResponseWriter, r *http.Request) {
cxt := r.Context() cxt := r.Context()
a, has := getAnyModel[yggdrasil.Pass](cxt, w, r.Body, y.validate, y.logger) a, has := getAnyModel[yggdrasil.Pass](cxt, w, r.Body, y.validate, y.logger)
if !has { if !has {
@ -76,8 +76,8 @@ func (y *Yggdrasil) Signout() httprouter.Handle {
} }
} }
func (y *Yggdrasil) Invalidate() httprouter.Handle { func (y *Yggdrasil) Invalidate() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { return func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(204) w.WriteHeader(204)
cxt := r.Context() cxt := r.Context()
a, has := getAnyModel[yggdrasil.ValidateToken](cxt, w, r.Body, y.validate, y.logger) a, has := getAnyModel[yggdrasil.ValidateToken](cxt, w, r.Body, y.validate, y.logger)
@ -95,8 +95,8 @@ func (y *Yggdrasil) Invalidate() httprouter.Handle {
} }
} }
func (y *Yggdrasil) Refresh() httprouter.Handle { func (y *Yggdrasil) Refresh() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { return func(w http.ResponseWriter, r *http.Request) {
cxt := r.Context() cxt := r.Context()
a, has := getAnyModel[yggdrasil.RefreshToken](cxt, w, r.Body, y.validate, y.logger) a, has := getAnyModel[yggdrasil.RefreshToken](cxt, w, r.Body, y.validate, y.logger)
if !has { if !has {
@ -117,10 +117,11 @@ func (y *Yggdrasil) Refresh() httprouter.Handle {
} }
} }
func (y *Yggdrasil) GetProfile() httprouter.Handle { func (y *Yggdrasil) GetProfile() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
uuid := p.ByName("uuid") uuid := chi.URLParamFromCtx(ctx, "uuid")
unsigned := r.FormValue("unsigned") unsigned := r.FormValue("unsigned")
unsignedBool := true unsignedBool := true
@ -151,8 +152,8 @@ func (y *Yggdrasil) GetProfile() httprouter.Handle {
} }
} }
func (y *Yggdrasil) BatchProfile() httprouter.Handle { func (y *Yggdrasil) BatchProfile() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
a, has := getAnyModel[[]string](ctx, w, r.Body, nil, y.logger) a, has := getAnyModel[[]string](ctx, w, r.Body, nil, y.logger)
if !has { if !has {
@ -172,8 +173,8 @@ func (y *Yggdrasil) BatchProfile() httprouter.Handle {
} }
} }
func (y *Yggdrasil) PlayerCertificates() httprouter.Handle { func (y *Yggdrasil) PlayerCertificates() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
token := y.getTokenbyAuthorization(ctx, w, r) token := y.getTokenbyAuthorization(ctx, w, r)
if token == "" { if token == "" {

View File

@ -10,11 +10,9 @@ import (
"net/url" "net/url"
"github.com/go-playground/validator/v10" "github.com/go-playground/validator/v10"
"github.com/julienschmidt/httprouter"
"github.com/samber/lo" "github.com/samber/lo"
"github.com/xmdhs/authlib-skin/config" "github.com/xmdhs/authlib-skin/config"
"github.com/xmdhs/authlib-skin/model/yggdrasil" "github.com/xmdhs/authlib-skin/model/yggdrasil"
yggdrasilM "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"
) )
@ -49,8 +47,8 @@ func getAnyModel[K any](ctx context.Context, w http.ResponseWriter, r io.Reader,
return a, true return a, true
} }
func (y *Yggdrasil) YggdrasilRoot() httprouter.Handle { func (y *Yggdrasil) YggdrasilRoot() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { return func(w http.ResponseWriter, r *http.Request) {
var host string var host string
if y.config.TextureBaseUrl != "" { if y.config.TextureBaseUrl != "" {
u := lo.Must(url.Parse(y.config.TextureBaseUrl)) u := lo.Must(url.Parse(y.config.TextureBaseUrl))
@ -64,11 +62,11 @@ func (y *Yggdrasil) YggdrasilRoot() httprouter.Handle {
homepage, _ := url.JoinPath(y.config.WebBaseUrl, "/login") homepage, _ := url.JoinPath(y.config.WebBaseUrl, "/login")
register, _ := url.JoinPath(y.config.WebBaseUrl, "/register") register, _ := url.JoinPath(y.config.WebBaseUrl, "/register")
w.Write(lo.Must1(json.Marshal(yggdrasilM.Yggdrasil{ w.Write(lo.Must1(json.Marshal(yggdrasil.Yggdrasil{
Meta: yggdrasilM.YggdrasilMeta{ Meta: yggdrasil.YggdrasilMeta{
ImplementationName: "authlib-skin", ImplementationName: "authlib-skin",
ImplementationVersion: "0.0.1", ImplementationVersion: "0.0.1",
Links: yggdrasilM.YggdrasilMetaLinks{ Links: yggdrasil.YggdrasilMetaLinks{
Homepage: homepage, Homepage: homepage,
Register: register, Register: register,
}, },
@ -82,8 +80,8 @@ func (y *Yggdrasil) YggdrasilRoot() httprouter.Handle {
} }
} }
func (y *Yggdrasil) TextureAssets() httprouter.Handle { func (y *Yggdrasil) TextureAssets() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "image/png") w.Header().Set("Content-Type", "image/png")
http.StripPrefix("/texture/", http.FileServer(http.Dir(y.config.TexturePath))).ServeHTTP(w, r) http.StripPrefix("/texture/", http.FileServer(http.Dir(y.config.TexturePath))).ServeHTTP(w, r)
} }

View File

@ -50,6 +50,7 @@ type UserList struct {
UserInfo UserInfo
Email string `json:"email"` Email string `json:"email"`
RegIp string `json:"reg_ip"` RegIp string `json:"reg_ip"`
Name string `json:"name"`
} }
type ChangeName struct { type ChangeName struct {

View File

@ -1,14 +1,75 @@
package route package route
import ( import (
"context"
"fmt"
"log/slog"
"net/http" "net/http"
"time"
"github.com/julienschmidt/httprouter" "github.com/go-chi/chi/v5/middleware"
) )
func warpHJSON(handle httprouter.Handle) httprouter.Handle { func warpHJSON(handle http.Handler) http.Handler {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8") w.Header().Set("Content-Type", "application/json; charset=utf-8")
handle(w, r, p) handle.ServeHTTP(w, r)
})
} }
func NewStructuredLogger(handler slog.Handler) func(next http.Handler) http.Handler {
return middleware.RequestLogger(&StructuredLogger{Logger: handler})
}
type StructuredLogger struct {
Logger slog.Handler
}
func (l *StructuredLogger) NewLogEntry(r *http.Request) middleware.LogEntry {
var logFields []slog.Attr
logFields = append(logFields, slog.String("ts", time.Now().UTC().Format(time.RFC1123)))
ctx := r.Context()
if reqID := middleware.GetReqID(ctx); reqID != "" {
logFields = append(logFields, slog.String("req_id", reqID))
}
scheme := "http"
if r.TLS != nil {
scheme = "https"
}
handler := l.Logger.WithAttrs(append(logFields,
slog.String("http_scheme", scheme),
slog.String("http_proto", r.Proto),
slog.String("http_method", r.Method),
slog.String("remote_addr", r.RemoteAddr),
slog.String("user_agent", r.UserAgent()),
slog.String("uri", fmt.Sprintf("%s://%s%s", scheme, r.Host, r.RequestURI))))
entry := StructuredLoggerEntry{Logger: slog.New(handler), ctx: ctx}
entry.Logger.LogAttrs(ctx, slog.LevelDebug, "request started")
return &entry
}
type StructuredLoggerEntry struct {
Logger *slog.Logger
ctx context.Context
}
func (l *StructuredLoggerEntry) Write(status, bytes int, header http.Header, elapsed time.Duration, extra interface{}) {
l.Logger.LogAttrs(l.ctx, slog.LevelDebug, "request complete",
slog.Int("resp_status", status),
slog.Int("resp_byte_length", bytes),
slog.Float64("resp_elapsed_ms", float64(elapsed.Nanoseconds())/1000000.0),
)
}
func (l *StructuredLoggerEntry) Panic(v interface{}, stack []byte) {
l.Logger.LogAttrs(l.ctx, slog.LevelDebug, "",
slog.String("stack", string(stack)),
slog.String("panic", fmt.Sprintf("%+v", v)),
)
} }

View File

@ -1,63 +1,73 @@
package route package route
import ( import (
"fmt" "log/slog"
"net/http" "net/http"
"github.com/julienschmidt/httprouter" "github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/go-chi/cors"
"github.com/xmdhs/authlib-skin/config"
"github.com/xmdhs/authlib-skin/handle" "github.com/xmdhs/authlib-skin/handle"
"github.com/xmdhs/authlib-skin/handle/yggdrasil" "github.com/xmdhs/authlib-skin/handle/yggdrasil"
) )
func NewRoute(yggService *yggdrasil.Yggdrasil, handel *handle.Handel) (*httprouter.Router, error) { func NewRoute(handelY *yggdrasil.Yggdrasil, handel *handle.Handel, c config.Config, sl slog.Handler) http.Handler {
r := httprouter.New() r := chi.NewRouter()
r.HandleOPTIONS = true r.Use(middleware.RequestID)
r.GlobalOPTIONS = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { r.Use(NewStructuredLogger(sl))
w.WriteHeader(204) r.Use(middleware.Recoverer)
r.Use(cors.AllowAll().Handler)
if c.RaelIP {
r.Use(middleware.RealIP)
}
r.Mount("/api/v1", newSkinApi(handel))
r.Mount("/api/yggdrasil", newYggdrasil(handelY))
r.Get("/texture/*", handelY.TextureAssets())
return r
}
func newYggdrasil(handelY *yggdrasil.Yggdrasil) http.Handler {
r := chi.NewRouter()
r.Use(warpHJSON)
r.Post("/authserver/authenticate", handelY.Authenticate())
r.Post("/authserver/validate", handelY.Validate())
r.Post("/authserver/signout", handelY.Signout())
r.Post("/authserver/invalidate", handelY.Invalidate())
r.Post("/authserver/refresh", handelY.Refresh())
r.Put("/api/user/profile/{uuid}/{textureType}", handelY.PutTexture())
r.Delete("/api/user/profile/{uuid}/{textureType}", handelY.DelTexture())
r.Get("/sessionserver/session/minecraft/profile/{uuid}", handelY.GetProfile())
r.Post("/api/profiles/minecraft", handelY.BatchProfile())
r.Post("/sessionserver/session/minecraft/join", handelY.SessionJoin())
r.Get("/sessionserver/session/minecraft/hasJoined", handelY.HasJoined())
r.Post("/minecraftservices/player/certificates", handelY.PlayerCertificates())
r.Get("/", handelY.YggdrasilRoot())
return r
}
func newSkinApi(handel *handle.Handel) http.Handler {
r := chi.NewRouter()
r.Put("/user/reg", handel.Reg())
r.Get("/config", handel.GetConfig())
r.Get("/user", handel.UserInfo())
r.Post("/user/password", handel.ChangePasswd())
r.Post("/user/name", handel.ChangeName())
r.Group(func(r chi.Router) {
r.Use(handel.NeedAdmin)
r.Get("/admin/users", handel.ListUser())
}) })
err := newYggdrasil(r, *yggService) return r
if err != nil {
return nil, fmt.Errorf("NewRoute: %w", err)
}
err = newSkinApi(r, handel)
if err != nil {
return nil, fmt.Errorf("NewRoute: %w", err)
}
return r, nil
}
func newYggdrasil(r *httprouter.Router, handelY yggdrasil.Yggdrasil) error {
r.POST("/api/yggdrasil/authserver/authenticate", warpHJSON(handelY.Authenticate()))
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", warpHJSON(handelY.Refresh()))
r.PUT("/api/yggdrasil/api/user/profile/:uuid/:textureType", handelY.PutTexture())
r.DELETE("/api/yggdrasil/api/user/profile/:uuid/:textureType", warpHJSON(handelY.DelTexture()))
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/sessionserver/session/minecraft/join", warpHJSON(handelY.SessionJoin()))
r.GET("/api/yggdrasil/sessionserver/session/minecraft/hasJoined", warpHJSON(handelY.HasJoined()))
r.POST("/api/yggdrasil/minecraftservices/player/certificates", warpHJSON(handelY.PlayerCertificates()))
r.GET("/api/yggdrasil", warpHJSON(handelY.YggdrasilRoot()))
r.GET("/api/yggdrasil/", warpHJSON(handelY.YggdrasilRoot()))
r.GET("/texture/*filepath", handelY.TextureAssets())
return nil
}
func newSkinApi(r *httprouter.Router, handel *handle.Handel) error {
r.PUT("/api/v1/user/reg", handel.Reg())
r.GET("/api/v1/config", handel.GetConfig())
r.GET("/api/v1/user", handel.UserInfo())
r.POST("/api/v1/user/password", handel.ChangePasswd())
r.POST("/api/v1/user/name", handel.ChangeName())
r.GET("/api/v1/admin/users", handel.NeedAdmin(handel.ListUser()))
return nil
} }

View File

@ -1,54 +1,19 @@
package server package server
import ( import (
"log/slog"
"net/http" "net/http"
"sync/atomic"
"time" "time"
"github.com/julienschmidt/httprouter"
"github.com/xmdhs/authlib-skin/config" "github.com/xmdhs/authlib-skin/config"
"github.com/xmdhs/authlib-skin/utils"
) )
func NewServer(c config.Config, sl *slog.Logger, route *httprouter.Router) (*http.Server, func()) { func NewServer(c config.Config, route http.Handler) (*http.Server, func()) {
trackid := atomic.Uint64{}
s := &http.Server{ s := &http.Server{
ReadTimeout: 10 * time.Second, ReadTimeout: 10 * time.Second,
ReadHeaderTimeout: 5 * time.Second, ReadHeaderTimeout: 5 * time.Second,
WriteTimeout: 20 * time.Second, WriteTimeout: 20 * time.Second,
Addr: c.Port, Addr: c.Port,
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { Handler: route,
ctx := r.Context()
if sl.Enabled(ctx, slog.LevelInfo) {
ip, _ := utils.GetIP(r, c.RaelIP)
trackid.Add(1)
ctx = setCtx(ctx, &reqInfo{
URL: r.URL.String(),
IP: ip,
TrackId: trackid.Load(),
})
r = r.WithContext(ctx)
}
if c.Debug && sl.Enabled(ctx, slog.LevelDebug) {
sl.DebugContext(ctx, r.Method)
}
cors(route).ServeHTTP(w, r)
}),
} }
return s, func() { s.Close() } return s, func() { s.Close() }
} }
func cors(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
header := w.Header()
if r.Header.Get("Access-Control-Request-Method") != "" {
header.Set("Access-Control-Allow-Methods", r.Header.Get("Access-Control-Request-Method"))
}
header.Set("Access-Control-Allow-Origin", "*")
header.Set("Access-Control-Allow-Headers", "*")
header.Set("Access-Control-Allow-Private-Network", "true")
header.Set("Access-Control-Max-Age", "3600")
h.ServeHTTP(w, r)
})
}

View File

@ -3,40 +3,18 @@ package server
import ( import (
"context" "context"
"log/slog" "log/slog"
"github.com/go-chi/chi/v5/middleware"
) )
type reqInfo struct {
URL string
IP string
TrackId uint64
}
type reqInfoKeyType string
var reqinfoKey reqInfoKeyType = "reqinfoKey"
func setCtx(ctx context.Context, r *reqInfo) context.Context {
return context.WithValue(ctx, reqinfoKey, r)
}
func getFromCtx(ctx context.Context) *reqInfo {
v := ctx.Value(reqinfoKey)
if v == nil {
return nil
}
return v.(*reqInfo)
}
type warpSlogHandle struct { type warpSlogHandle struct {
slog.Handler slog.Handler
} }
func (w *warpSlogHandle) Handle(ctx context.Context, r slog.Record) error { func (w *warpSlogHandle) Handle(ctx context.Context, r slog.Record) error {
if w.Enabled(ctx, slog.LevelInfo) { id := middleware.GetReqID(ctx)
ri := getFromCtx(ctx) if id != "" {
if ri != nil { r.AddAttrs(slog.String("trackID", id))
r.AddAttrs(slog.String("ip", ri.IP), slog.String("url", ri.URL), slog.Uint64("trackID", ri.TrackId))
}
} }
return w.Handler.Handle(ctx, r) return w.Handler.Handle(ctx, r)
} }

View File

@ -54,13 +54,8 @@ func InitializeRoute(ctx context.Context, c config.Config) (*http.Server, func()
httpClient := ProvideHttpClient() httpClient := ProvideHttpClient()
webService := service.NewWebService(c, client, httpClient, cache, privateKey) webService := service.NewWebService(c, client, httpClient, cache, privateKey)
handel := handle.NewHandel(webService, validate, c, logger) handel := handle.NewHandel(webService, validate, c, logger)
router, err := route.NewRoute(yggdrasil3, handel) httpHandler := route.NewRoute(yggdrasil3, handel, c, handler)
if err != nil { server, cleanup3 := NewServer(c, httpHandler)
cleanup2()
cleanup()
return nil, nil, err
}
server, cleanup3 := NewServer(c, logger, router)
return server, func() { return server, func() {
cleanup3() cleanup3()
cleanup2() cleanup2()

View File

@ -36,6 +36,9 @@ func (w *WebService) ListUser(ctx context.Context, page int) ([]model.UserList,
ul := make([]model.UserList, 0, len(u)) ul := make([]model.UserList, 0, len(u))
for _, v := range u { for _, v := range u {
if v.Edges.Profile == nil {
continue
}
ul = append(ul, model.UserList{ ul = append(ul, model.UserList{
UserInfo: model.UserInfo{ UserInfo: model.UserInfo{
UID: v.ID, UID: v.ID,
@ -44,6 +47,7 @@ func (w *WebService) ListUser(ctx context.Context, page int) ([]model.UserList,
}, },
Email: v.Email, Email: v.Email,
RegIp: v.RegIP, RegIp: v.RegIP,
Name: v.Edges.Profile.Name,
}) })
} }

View File

@ -124,11 +124,12 @@ func (w *WebService) ChangePasswd(ctx context.Context, p model.ChangePasswd, tok
return fmt.Errorf("ChangePasswd: %w", ErrPassWord) return fmt.Errorf("ChangePasswd: %w", ErrPassWord)
} }
pass, salt := utils.Argon2ID(p.New) pass, salt := utils.Argon2ID(p.New)
if u.Edges.Token != nil {
err = w.client.UserToken.UpdateOne(u.Edges.Token).AddTokenID(1).Exec(ctx) err := w.client.UserToken.UpdateOne(u.Edges.Token).AddTokenID(1).Exec(ctx)
if err != nil { if err != nil {
return fmt.Errorf("ChangePasswd: %w", err) return fmt.Errorf("ChangePasswd: %w", err)
} }
}
err = w.cache.Del([]byte("auth" + strconv.Itoa(t.UID))) err = w.cache.Del([]byte("auth" + strconv.Itoa(t.UID)))
if err != nil { if err != nil {
return fmt.Errorf("ChangePasswd: %w", err) return fmt.Errorf("ChangePasswd: %w", err)

View File

@ -95,6 +95,10 @@ func (y *Yggdrasil) Authenticate(cxt context.Context, auth yggdrasil.Authenticat
if err != nil { if err != nil {
return yggdrasil.Token{}, fmt.Errorf("Authenticate: %w", err) return yggdrasil.Token{}, fmt.Errorf("Authenticate: %w", err)
} }
if u.Edges.Profile == nil {
return yggdrasil.Token{}, fmt.Errorf("Authenticate: %w", ErrUserDisable)
}
jwts, err := newJwtToken(y.prikey, strconv.FormatUint(utoken.TokenID, 10), clientToken, u.Edges.Profile.UUID, u.ID) jwts, err := newJwtToken(y.prikey, strconv.FormatUint(utoken.TokenID, 10), clientToken, u.Edges.Profile.UUID, u.ID)
if err != nil { if err != nil {
return yggdrasil.Token{}, fmt.Errorf("Authenticate: %w", err) return yggdrasil.Token{}, fmt.Errorf("Authenticate: %w", err)

View File

@ -4,30 +4,9 @@ import (
"fmt" "fmt"
"net" "net"
"net/http" "net/http"
"strings"
) )
func GetIP(r *http.Request, fromHeader bool) (string, error) { func GetIP(r *http.Request) (string, error) {
if fromHeader {
//Get IP from the X-REAL-IP header
ip := r.Header.Get("X-REAL-IP")
netIP := net.ParseIP(ip)
if netIP != nil {
return ip, nil
}
//Get IP from X-FORWARDED-FOR header
ips := r.Header.Get("X-FORWARDED-FOR")
splitIps := strings.Split(ips, ",")
for _, ip := range splitIps {
netIP := net.ParseIP(ip)
if netIP != nil {
return ip, nil
}
}
}
//Get IP from RemoteAddr
ip, _, err := net.SplitHostPort(r.RemoteAddr) ip, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil { if err != nil {
return "", err return "", err