From b36f7f3085e894e8fe97341aa08564ec55886d03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=97=E5=AD=90?= Date: Thu, 17 Oct 2024 18:40:27 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=AF=86=E7=A0=81?= =?UTF-8?q?=E5=A4=8D=E6=9D=82=E5=BA=A6=E9=AA=8C=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/apps/mysql/request.go | 2 +- internal/apps/pureftpd/request.go | 4 +-- internal/apps/toolbox/request.go | 2 +- internal/apps/toolbox/service.go | 5 ---- internal/http/request/setting.go | 2 +- internal/http/request/website.go | 2 +- internal/http/rule/password.go | 50 +++++++++++++++++++++++++++++++ internal/http/rule/rule.go | 13 ++++++++ pkg/firewall/firewall.go | 4 +++ 9 files changed, 73 insertions(+), 11 deletions(-) create mode 100644 internal/http/rule/password.go diff --git a/internal/apps/mysql/request.go b/internal/apps/mysql/request.go index 66c08512..50f68ae1 100644 --- a/internal/apps/mysql/request.go +++ b/internal/apps/mysql/request.go @@ -5,5 +5,5 @@ type UpdateConfig struct { } type SetRootPassword struct { - Password string `form:"password" json:"password" validate:"required"` + Password string `form:"password" json:"password" validate:"required,password"` } diff --git a/internal/apps/pureftpd/request.go b/internal/apps/pureftpd/request.go index 4923a85b..415284bb 100644 --- a/internal/apps/pureftpd/request.go +++ b/internal/apps/pureftpd/request.go @@ -2,7 +2,7 @@ package pureftpd type Create struct { Username string `form:"username" json:"username" validate:"required"` - Password string `form:"password" json:"password" validate:"required"` + Password string `form:"password" json:"password" validate:"required,password"` Path string `form:"path" json:"path" validate:"required"` } @@ -12,7 +12,7 @@ type Delete struct { type ChangePassword struct { Username string `form:"username" json:"username" validate:"required"` - Password string `form:"password" json:"password" validate:"required"` + Password string `form:"password" json:"password" validate:"required,password"` } type UpdatePort struct { diff --git a/internal/apps/toolbox/request.go b/internal/apps/toolbox/request.go index 7bf0d161..aa95d7ca 100644 --- a/internal/apps/toolbox/request.go +++ b/internal/apps/toolbox/request.go @@ -18,5 +18,5 @@ type Hosts struct { } type Password struct { - Password string `form:"password" json:"password" validate:"required"` + Password string `form:"password" json:"password" validate:"required,password"` } diff --git a/internal/apps/toolbox/service.go b/internal/apps/toolbox/service.go index d06a5bb1..7855d420 100644 --- a/internal/apps/toolbox/service.go +++ b/internal/apps/toolbox/service.go @@ -251,11 +251,6 @@ func (s *Service) UpdateRootPassword(w http.ResponseWriter, r *http.Request) { return } - if !regexp.MustCompile(`^[a-zA-Z0-9·~!@#$%^&*()_+-=\[\]{};:'",./<>?]{6,20}$`).MatchString(req.Password) { - service.Error(w, http.StatusUnprocessableEntity, "密码必须为 6-20 位字母、数字或特殊字符") - return - } - req.Password = strings.ReplaceAll(req.Password, `'`, `\'`) if _, err = shell.Execf(`yes '%s' | passwd root`, req.Password); err != nil { service.Error(w, http.StatusInternalServerError, "%v", err) diff --git a/internal/http/request/setting.go b/internal/http/request/setting.go index 7ceadd8d..c6825fff 100644 --- a/internal/http/request/setting.go +++ b/internal/http/request/setting.go @@ -8,7 +8,7 @@ type PanelSetting struct { WebsitePath string `json:"website_path" validate:"required"` BackupPath string `json:"backup_path" validate:"required"` Username string `json:"username" validate:"required"` - Password string `json:"password"` + Password string `json:"password" validate:"password"` Email string `json:"email" validate:"required"` Port int `json:"port" validate:"required,number,gte=1,lte=65535"` HTTPS bool `json:"https"` diff --git a/internal/http/request/website.go b/internal/http/request/website.go index 1b309889..791290bf 100644 --- a/internal/http/request/website.go +++ b/internal/http/request/website.go @@ -17,7 +17,7 @@ type WebsiteCreate struct { DBType string `form:"db_type" json:"db_type"` DBName string `form:"db_name" json:"db_name"` DBUser string `form:"db_user" json:"db_user"` - DBPassword string `form:"db_password" json:"db_password"` + DBPassword string `form:"db_password" json:"db_password" validate:"password"` } type WebsiteDelete struct { diff --git a/internal/http/rule/password.go b/internal/http/rule/password.go new file mode 100644 index 00000000..cc8948b3 --- /dev/null +++ b/internal/http/rule/password.go @@ -0,0 +1,50 @@ +package rule + +import ( + "unicode" + + "github.com/go-playground/validator/v10" +) + +type Password struct{} + +func NewPassword() *Password { + return &Password{} +} + +// Password 密码复杂度校验 +func (r *Password) Password(fl validator.FieldLevel) bool { + password := fl.Field().String() + // 不对空密码进行校验,有需要可以使用 required 标签 + if password == "" { + return true + } + + var hasUpper, hasLower, hasNumber, hasSpecial bool + if len(password) < 8 || len(password) > 20 { + return false + } + + for _, char := range password { + switch { + case unicode.IsUpper(char): + hasUpper = true + case unicode.IsLower(char): + hasLower = true + case unicode.IsNumber(char): + hasNumber = true + case unicode.IsPunct(char) || unicode.IsSymbol(char): + hasSpecial = true + } + } + + // 至少包含两类字符组合 + valid := (hasUpper && hasLower) || + (hasUpper && hasNumber) || + (hasUpper && hasSpecial) || + (hasLower && hasNumber) || + (hasLower && hasSpecial) || + (hasNumber && hasSpecial) + + return valid +} diff --git a/internal/http/rule/rule.go b/internal/http/rule/rule.go index 37e18172..6003ad9b 100644 --- a/internal/http/rule/rule.go +++ b/internal/http/rule/rule.go @@ -17,6 +17,9 @@ func RegisterRules(v *validator.Validate) error { if err := v.RegisterValidation("regexp", NewRegexp().Regexp); err != nil { return err } + if err := v.RegisterValidation("password", NewPassword().Password); err != nil { + return err + } if err := v.RegisterTranslation("exists", *app.Translator, func(ut ut.Translator) error { @@ -48,6 +51,16 @@ func RegisterRules(v *validator.Validate) error { }); err != nil { return err } + if err := v.RegisterTranslation("password", *app.Translator, + func(ut ut.Translator) error { + return ut.Add("password", "密码不满足要求(8-20位,至少包含大小写字母、数字、特殊字符中的两种)", true) + }, + func(ut ut.Translator, fe validator.FieldError) string { + t, _ := ut.T("password") + return t + }); err != nil { + return err + } return nil } diff --git a/pkg/firewall/firewall.go b/pkg/firewall/firewall.go index b1c2f3f6..7be1defa 100644 --- a/pkg/firewall/firewall.go +++ b/pkg/firewall/firewall.go @@ -147,6 +147,10 @@ func (r *Firewall) Port(rule FireInfo, operation Operation) error { return r.RichRules(rule, operation) } + // 未设置协议默认为tcp/udp + if rule.Protocol == "" { + rule.Protocol = ProtocolTCPUDP + } protocols := strings.Split(string(rule.Protocol), "/") for protocol := range slices.Values(protocols) { stdout, err := shell.Execf("firewall-cmd --zone=public --%s-port=%d-%d/%s --permanent", operation, rule.PortStart, rule.PortEnd, protocol)