From 6cf90d47f70250bacde65c47e004d189b89aea3e Mon Sep 17 00:00:00 2001 From: xmdhs Date: Thu, 7 Sep 2023 00:54:53 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B3=A8=E5=86=8C=E8=AE=B0=E5=BD=95=20ip?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/ent/migrate/schema.go | 5 +-- db/ent/mutation.go | 56 +++++++++++++++++++++++++++++++- db/ent/schema/user.go | 3 ++ db/ent/user.go | 13 +++++++- db/ent/user/user.go | 8 +++++ db/ent/user/where.go | 70 ++++++++++++++++++++++++++++++++++++++++ db/ent/user_create.go | 13 ++++++++ db/ent/user_update.go | 18 +++++++++++ go.mod | 2 ++ go.sum | 4 +++ handle/user.go | 26 ++++++++++++++- model/const.go | 3 +- service/user.go | 3 +- 13 files changed, 217 insertions(+), 7 deletions(-) diff --git a/db/ent/migrate/schema.go b/db/ent/migrate/schema.go index 8abe3d3..cb5d917 100644 --- a/db/ent/migrate/schema.go +++ b/db/ent/migrate/schema.go @@ -43,6 +43,7 @@ var ( {Name: "email", Type: field.TypeString, Unique: true, SchemaType: map[string]string{"mysql": "VARCHAR(30)"}}, {Name: "password", Type: field.TypeString, SchemaType: map[string]string{"mysql": "VARCHAR(80)"}}, {Name: "salt", Type: field.TypeString, SchemaType: map[string]string{"mysql": "VARCHAR(50)"}}, + {Name: "reg_ip", Type: field.TypeString, SchemaType: map[string]string{"mysql": "VARCHAR(32)"}}, {Name: "state", Type: field.TypeInt}, {Name: "reg_time", Type: field.TypeInt64}, {Name: "user_token", Type: field.TypeInt, Nullable: true}, @@ -56,13 +57,13 @@ var ( ForeignKeys: []*schema.ForeignKey{ { Symbol: "users_user_tokens_token", - Columns: []*schema.Column{UsersColumns[6]}, + Columns: []*schema.Column{UsersColumns[7]}, RefColumns: []*schema.Column{UserTokensColumns[0]}, OnDelete: schema.Cascade, }, { Symbol: "users_skins_skin", - Columns: []*schema.Column{UsersColumns[7]}, + Columns: []*schema.Column{UsersColumns[8]}, RefColumns: []*schema.Column{SkinsColumns[0]}, OnDelete: schema.SetNull, }, diff --git a/db/ent/mutation.go b/db/ent/mutation.go index 31cbcfd..d1ef425 100644 --- a/db/ent/mutation.go +++ b/db/ent/mutation.go @@ -578,6 +578,7 @@ type UserMutation struct { email *string password *string salt *string + reg_ip *string state *int addstate *int reg_time *int64 @@ -803,6 +804,42 @@ func (m *UserMutation) ResetSalt() { m.salt = nil } +// SetRegIP sets the "reg_ip" field. +func (m *UserMutation) SetRegIP(s string) { + m.reg_ip = &s +} + +// RegIP returns the value of the "reg_ip" field in the mutation. +func (m *UserMutation) RegIP() (r string, exists bool) { + v := m.reg_ip + if v == nil { + return + } + return *v, true +} + +// OldRegIP returns the old "reg_ip" field's value of the User entity. +// If the User object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *UserMutation) OldRegIP(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldRegIP is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldRegIP requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldRegIP: %w", err) + } + return oldValue.RegIP, nil +} + +// ResetRegIP resets all changes to the "reg_ip" field. +func (m *UserMutation) ResetRegIP() { + m.reg_ip = nil +} + // SetState sets the "state" field. func (m *UserMutation) SetState(i int) { m.state = &i @@ -1120,7 +1157,7 @@ func (m *UserMutation) Type() string { // order to get all numeric fields that were incremented/decremented, call // AddedFields(). func (m *UserMutation) Fields() []string { - fields := make([]string, 0, 5) + fields := make([]string, 0, 6) if m.email != nil { fields = append(fields, user.FieldEmail) } @@ -1130,6 +1167,9 @@ func (m *UserMutation) Fields() []string { if m.salt != nil { fields = append(fields, user.FieldSalt) } + if m.reg_ip != nil { + fields = append(fields, user.FieldRegIP) + } if m.state != nil { fields = append(fields, user.FieldState) } @@ -1150,6 +1190,8 @@ func (m *UserMutation) Field(name string) (ent.Value, bool) { return m.Password() case user.FieldSalt: return m.Salt() + case user.FieldRegIP: + return m.RegIP() case user.FieldState: return m.State() case user.FieldRegTime: @@ -1169,6 +1211,8 @@ func (m *UserMutation) OldField(ctx context.Context, name string) (ent.Value, er return m.OldPassword(ctx) case user.FieldSalt: return m.OldSalt(ctx) + case user.FieldRegIP: + return m.OldRegIP(ctx) case user.FieldState: return m.OldState(ctx) case user.FieldRegTime: @@ -1203,6 +1247,13 @@ func (m *UserMutation) SetField(name string, value ent.Value) error { } m.SetSalt(v) return nil + case user.FieldRegIP: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetRegIP(v) + return nil case user.FieldState: v, ok := value.(int) if !ok { @@ -1302,6 +1353,9 @@ func (m *UserMutation) ResetField(name string) error { case user.FieldSalt: m.ResetSalt() return nil + case user.FieldRegIP: + m.ResetRegIP() + return nil case user.FieldState: m.ResetState() return nil diff --git a/db/ent/schema/user.go b/db/ent/schema/user.go index 0ab7fca..e485feb 100644 --- a/db/ent/schema/user.go +++ b/db/ent/schema/user.go @@ -26,6 +26,9 @@ func (User) Fields() []ent.Field { field.String("salt").SchemaType(map[string]string{ dialect.MySQL: "VARCHAR(50)", }), + field.String("reg_ip").SchemaType(map[string]string{ + dialect.MySQL: "VARCHAR(32)", + }), // 二进制状态位,保留 field.Int("state"), field.Int64("reg_time"), diff --git a/db/ent/user.go b/db/ent/user.go index 53960ca..d6d1912 100644 --- a/db/ent/user.go +++ b/db/ent/user.go @@ -25,6 +25,8 @@ type User struct { Password string `json:"password,omitempty"` // Salt holds the value of the "salt" field. Salt string `json:"salt,omitempty"` + // RegIP holds the value of the "reg_ip" field. + RegIP string `json:"reg_ip,omitempty"` // State holds the value of the "state" field. State int `json:"state,omitempty"` // RegTime holds the value of the "reg_time" field. @@ -107,7 +109,7 @@ func (*User) scanValues(columns []string) ([]any, error) { switch columns[i] { case user.FieldID, user.FieldState, user.FieldRegTime: values[i] = new(sql.NullInt64) - case user.FieldEmail, user.FieldPassword, user.FieldSalt: + case user.FieldEmail, user.FieldPassword, user.FieldSalt, user.FieldRegIP: values[i] = new(sql.NullString) case user.ForeignKeys[0]: // user_token values[i] = new(sql.NullInt64) @@ -152,6 +154,12 @@ func (u *User) assignValues(columns []string, values []any) error { } else if value.Valid { u.Salt = value.String } + case user.FieldRegIP: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field reg_ip", values[i]) + } else if value.Valid { + u.RegIP = value.String + } case user.FieldState: if value, ok := values[i].(*sql.NullInt64); !ok { return fmt.Errorf("unexpected type %T for field state", values[i]) @@ -243,6 +251,9 @@ func (u *User) String() string { builder.WriteString("salt=") builder.WriteString(u.Salt) builder.WriteString(", ") + builder.WriteString("reg_ip=") + builder.WriteString(u.RegIP) + builder.WriteString(", ") builder.WriteString("state=") builder.WriteString(fmt.Sprintf("%v", u.State)) builder.WriteString(", ") diff --git a/db/ent/user/user.go b/db/ent/user/user.go index 5edecf7..7cabaab 100644 --- a/db/ent/user/user.go +++ b/db/ent/user/user.go @@ -18,6 +18,8 @@ const ( FieldPassword = "password" // FieldSalt holds the string denoting the salt field in the database. FieldSalt = "salt" + // FieldRegIP holds the string denoting the reg_ip field in the database. + FieldRegIP = "reg_ip" // FieldState holds the string denoting the state field in the database. FieldState = "state" // FieldRegTime holds the string denoting the reg_time field in the database. @@ -68,6 +70,7 @@ var Columns = []string{ FieldEmail, FieldPassword, FieldSalt, + FieldRegIP, FieldState, FieldRegTime, } @@ -117,6 +120,11 @@ func BySalt(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldSalt, opts...).ToFunc() } +// ByRegIP orders the results by the reg_ip field. +func ByRegIP(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldRegIP, opts...).ToFunc() +} + // ByState orders the results by the state field. func ByState(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldState, opts...).ToFunc() diff --git a/db/ent/user/where.go b/db/ent/user/where.go index c520eb4..f13fa5c 100644 --- a/db/ent/user/where.go +++ b/db/ent/user/where.go @@ -68,6 +68,11 @@ func Salt(v string) predicate.User { return predicate.User(sql.FieldEQ(FieldSalt, v)) } +// RegIP applies equality check predicate on the "reg_ip" field. It's identical to RegIPEQ. +func RegIP(v string) predicate.User { + return predicate.User(sql.FieldEQ(FieldRegIP, v)) +} + // State applies equality check predicate on the "state" field. It's identical to StateEQ. func State(v int) predicate.User { return predicate.User(sql.FieldEQ(FieldState, v)) @@ -273,6 +278,71 @@ func SaltContainsFold(v string) predicate.User { return predicate.User(sql.FieldContainsFold(FieldSalt, v)) } +// RegIPEQ applies the EQ predicate on the "reg_ip" field. +func RegIPEQ(v string) predicate.User { + return predicate.User(sql.FieldEQ(FieldRegIP, v)) +} + +// RegIPNEQ applies the NEQ predicate on the "reg_ip" field. +func RegIPNEQ(v string) predicate.User { + return predicate.User(sql.FieldNEQ(FieldRegIP, v)) +} + +// RegIPIn applies the In predicate on the "reg_ip" field. +func RegIPIn(vs ...string) predicate.User { + return predicate.User(sql.FieldIn(FieldRegIP, vs...)) +} + +// RegIPNotIn applies the NotIn predicate on the "reg_ip" field. +func RegIPNotIn(vs ...string) predicate.User { + return predicate.User(sql.FieldNotIn(FieldRegIP, vs...)) +} + +// RegIPGT applies the GT predicate on the "reg_ip" field. +func RegIPGT(v string) predicate.User { + return predicate.User(sql.FieldGT(FieldRegIP, v)) +} + +// RegIPGTE applies the GTE predicate on the "reg_ip" field. +func RegIPGTE(v string) predicate.User { + return predicate.User(sql.FieldGTE(FieldRegIP, v)) +} + +// RegIPLT applies the LT predicate on the "reg_ip" field. +func RegIPLT(v string) predicate.User { + return predicate.User(sql.FieldLT(FieldRegIP, v)) +} + +// RegIPLTE applies the LTE predicate on the "reg_ip" field. +func RegIPLTE(v string) predicate.User { + return predicate.User(sql.FieldLTE(FieldRegIP, v)) +} + +// RegIPContains applies the Contains predicate on the "reg_ip" field. +func RegIPContains(v string) predicate.User { + return predicate.User(sql.FieldContains(FieldRegIP, v)) +} + +// RegIPHasPrefix applies the HasPrefix predicate on the "reg_ip" field. +func RegIPHasPrefix(v string) predicate.User { + return predicate.User(sql.FieldHasPrefix(FieldRegIP, v)) +} + +// RegIPHasSuffix applies the HasSuffix predicate on the "reg_ip" field. +func RegIPHasSuffix(v string) predicate.User { + return predicate.User(sql.FieldHasSuffix(FieldRegIP, v)) +} + +// RegIPEqualFold applies the EqualFold predicate on the "reg_ip" field. +func RegIPEqualFold(v string) predicate.User { + return predicate.User(sql.FieldEqualFold(FieldRegIP, v)) +} + +// RegIPContainsFold applies the ContainsFold predicate on the "reg_ip" field. +func RegIPContainsFold(v string) predicate.User { + return predicate.User(sql.FieldContainsFold(FieldRegIP, v)) +} + // StateEQ applies the EQ predicate on the "state" field. func StateEQ(v int) predicate.User { return predicate.User(sql.FieldEQ(FieldState, v)) diff --git a/db/ent/user_create.go b/db/ent/user_create.go index 2f7f73d..1aa2dc8 100644 --- a/db/ent/user_create.go +++ b/db/ent/user_create.go @@ -40,6 +40,12 @@ func (uc *UserCreate) SetSalt(s string) *UserCreate { return uc } +// SetRegIP sets the "reg_ip" field. +func (uc *UserCreate) SetRegIP(s string) *UserCreate { + uc.mutation.SetRegIP(s) + return uc +} + // SetState sets the "state" field. func (uc *UserCreate) SetState(i int) *UserCreate { uc.mutation.SetState(i) @@ -167,6 +173,9 @@ func (uc *UserCreate) check() error { if _, ok := uc.mutation.Salt(); !ok { return &ValidationError{Name: "salt", err: errors.New(`ent: missing required field "User.salt"`)} } + if _, ok := uc.mutation.RegIP(); !ok { + return &ValidationError{Name: "reg_ip", err: errors.New(`ent: missing required field "User.reg_ip"`)} + } if _, ok := uc.mutation.State(); !ok { return &ValidationError{Name: "state", err: errors.New(`ent: missing required field "User.state"`)} } @@ -211,6 +220,10 @@ func (uc *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) { _spec.SetField(user.FieldSalt, field.TypeString, value) _node.Salt = value } + if value, ok := uc.mutation.RegIP(); ok { + _spec.SetField(user.FieldRegIP, field.TypeString, value) + _node.RegIP = value + } if value, ok := uc.mutation.State(); ok { _spec.SetField(user.FieldState, field.TypeInt, value) _node.State = value diff --git a/db/ent/user_update.go b/db/ent/user_update.go index 5bd1e91..a0413f7 100644 --- a/db/ent/user_update.go +++ b/db/ent/user_update.go @@ -48,6 +48,12 @@ func (uu *UserUpdate) SetSalt(s string) *UserUpdate { return uu } +// SetRegIP sets the "reg_ip" field. +func (uu *UserUpdate) SetRegIP(s string) *UserUpdate { + uu.mutation.SetRegIP(s) + return uu +} + // SetState sets the "state" field. func (uu *UserUpdate) SetState(i int) *UserUpdate { uu.mutation.ResetState() @@ -235,6 +241,9 @@ func (uu *UserUpdate) sqlSave(ctx context.Context) (n int, err error) { if value, ok := uu.mutation.Salt(); ok { _spec.SetField(user.FieldSalt, field.TypeString, value) } + if value, ok := uu.mutation.RegIP(); ok { + _spec.SetField(user.FieldRegIP, field.TypeString, value) + } if value, ok := uu.mutation.State(); ok { _spec.SetField(user.FieldState, field.TypeInt, value) } @@ -417,6 +426,12 @@ func (uuo *UserUpdateOne) SetSalt(s string) *UserUpdateOne { return uuo } +// SetRegIP sets the "reg_ip" field. +func (uuo *UserUpdateOne) SetRegIP(s string) *UserUpdateOne { + uuo.mutation.SetRegIP(s) + return uuo +} + // SetState sets the "state" field. func (uuo *UserUpdateOne) SetState(i int) *UserUpdateOne { uuo.mutation.ResetState() @@ -634,6 +649,9 @@ func (uuo *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) if value, ok := uuo.mutation.Salt(); ok { _spec.SetField(user.FieldSalt, field.TypeString, value) } + if value, ok := uuo.mutation.RegIP(); ok { + _spec.SetField(user.FieldRegIP, field.TypeString, value) + } if value, ok := uuo.mutation.State(); ok { _spec.SetField(user.FieldState, field.TypeInt, value) } diff --git a/go.mod b/go.mod index 6b7efd6..c57d790 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,9 @@ require ( github.com/hashicorp/hcl/v2 v2.13.0 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect + github.com/samber/lo v1.38.1 // indirect github.com/zclconf/go-cty v1.8.0 // indirect + golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect golang.org/x/mod v0.10.0 // indirect golang.org/x/net v0.8.0 // indirect golang.org/x/sys v0.7.0 // indirect diff --git a/go.sum b/go.sum index d4a65ae..07920e9 100644 --- a/go.sum +++ b/go.sum @@ -70,6 +70,8 @@ github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzC github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= +github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -87,6 +89,8 @@ github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUA golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM= +golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= diff --git a/handle/user.go b/handle/user.go index 27f48d4..73890a5 100644 --- a/handle/user.go +++ b/handle/user.go @@ -2,9 +2,12 @@ package handle import ( "errors" + "fmt" "net/http" + "net/netip" "github.com/julienschmidt/httprouter" + "github.com/samber/lo" "github.com/xmdhs/authlib-skin/model" "github.com/xmdhs/authlib-skin/service" "github.com/xmdhs/authlib-skin/utils" @@ -20,7 +23,13 @@ func (h *Handel) Reg() httprouter.Handle { handleError(ctx, w, err.Error(), model.ErrInput, 400) return } - err = h.webService.Reg(ctx, u) + rip, err := getPrefix(r, h.config.RaelIP) + if err != nil { + h.logger.WarnContext(ctx, err.Error()) + handleError(ctx, w, err.Error(), model.ErrUnknown, 500) + return + } + err = h.webService.Reg(ctx, u, rip) if err != nil { if errors.Is(err, service.ErrExistUser) { h.logger.DebugContext(ctx, err.Error()) @@ -33,3 +42,18 @@ func (h *Handel) Reg() httprouter.Handle { } } } + +func getPrefix(r *http.Request, fromHeader bool) (string, error) { + ip, err := utils.GetIP(r, fromHeader) + if err != nil { + return "", fmt.Errorf("getPrefix: %w", err) + } + ipa, err := netip.ParseAddr(ip) + if err != nil { + return "", fmt.Errorf("getPrefix: %w", err) + } + if ipa.Is6() { + return lo.Must1(ipa.Prefix(48)).String(), nil + } + return ipa.String(), nil +} diff --git a/model/const.go b/model/const.go index 7f5cb58..6db5156 100644 --- a/model/const.go +++ b/model/const.go @@ -3,7 +3,8 @@ package model type APIStatus int const ( - OK APIStatus = iota + ErrUnknown APIStatus = iota - 1 + OK ErrInput ErrService ErrExistUser diff --git a/service/user.go b/service/user.go index ee26b01..105161b 100644 --- a/service/user.go +++ b/service/user.go @@ -22,7 +22,7 @@ var ( ErrExitsName = errors.New("用户名已存在") ) -func (w *WebService) Reg(ctx context.Context, u model.User) error { +func (w *WebService) Reg(ctx context.Context, u model.User, ip string) error { var userUuid string if w.config.OfflineUUID { userUuid = uuidGen(u.Name) @@ -51,6 +51,7 @@ func (w *WebService) Reg(ctx context.Context, u model.User) error { SetPassword(p). SetSalt(s). SetRegTime(time.Now().Unix()). + SetRegIP(""). SetState(0).Save(ctx) if err != nil { return err