This is an automated email from the ASF dual-hosted git repository. tianxiaoliang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git
The following commit(s) were added to refs/heads/master by this push: new 50c787f Use foundation/validator instead (#184) 50c787f is described below commit 50c787fe1dbb6917c3c95497c5a0b15f25a19d0f Author: little-cui <sure_0...@qq.com> AuthorDate: Thu Jun 3 20:06:35 2021 +0800 Use foundation/validator instead (#184) --- go.mod | 7 +- go.sum | 10 ++ pkg/model/db_schema.go | 26 ++--- pkg/validate/instance.go | 49 ---------- pkg/validate/instance_test.go | 125 ------------------------ pkg/validate/rule.go | 90 ----------------- pkg/validate/rule_test.go | 39 -------- pkg/validate/validator.go | 87 ----------------- pkg/validate/validator_test.go | 36 ------- pkg/validator/rule.go | 46 +++++++++ pkg/validator/rule_test.go | 173 +++++++++++++++++++++++++++++++++ server/resource/v1/kv_resource.go | 10 +- server/resource/v1/kv_resource_test.go | 4 - server/server.go | 4 +- test/init.go | 2 + 15 files changed, 253 insertions(+), 455 deletions(-) diff --git a/go.mod b/go.mod index b10cd0d..539d13b 100644 --- a/go.mod +++ b/go.mod @@ -2,16 +2,13 @@ module github.com/apache/servicecomb-kie require ( github.com/emicklei/go-restful v2.12.0+incompatible - github.com/go-chassis/cari v0.2.0 + github.com/go-chassis/cari v0.4.1-0.20210528013912-6da8395f7ff9 + github.com/go-chassis/foundation v0.3.1-0.20210602072914-a580bed505d0 github.com/go-chassis/go-archaius v1.5.2-0.20210301074935-e4694f6b077b github.com/go-chassis/go-chassis/v2 v2.1.2-0.20210308033545-985e98e20637 github.com/go-chassis/openlog v1.1.2 github.com/go-chassis/seclog v1.3.0 - github.com/go-playground/universal-translator v0.17.0 - github.com/go-playground/validator v9.31.0+incompatible github.com/hashicorp/serf v0.9.5 - github.com/leodido/go-urn v1.2.1 // indirect - github.com/mitchellh/mapstructure v1.3.3 // indirect github.com/satori/go.uuid v1.2.0 github.com/stretchr/testify v1.6.1 github.com/urfave/cli v1.22.4 diff --git a/go.sum b/go.sum index e61b066..f0e08bd 100644 --- a/go.sum +++ b/go.sum @@ -120,10 +120,16 @@ github.com/go-chassis/cari v0.0.2-0.20210208095358-3bccdf2ce456 h1:n81PUcR0Qrapi github.com/go-chassis/cari v0.0.2-0.20210208095358-3bccdf2ce456/go.mod h1:MgtsEI0AM4Ush6Lyw27z9Gk4nQ/8GWTSXrFzupawWDM= github.com/go-chassis/cari v0.2.0 h1:29Rsisbq/bKc79OCZdD2TU0aGr8UBH/i0fjUniMh0+Q= github.com/go-chassis/cari v0.2.0/go.mod h1:Ie2lW11Y5ZFClY9z7bhAwK6BoNxqGSf3fYGs4mPFs74= +github.com/go-chassis/cari v0.4.0 h1:2rJ7pB4dfZIu5/HQwwJhmybC1n/0MXWkKieoHCu4tQc= +github.com/go-chassis/cari v0.4.0/go.mod h1:av/19fqwEP4eOC8unL/z67AAbFDwXUCko6SKa4Avrd8= +github.com/go-chassis/cari v0.4.1-0.20210528013912-6da8395f7ff9 h1:UxNOY1mnK7i9qRYeu0d2jsVItfoV0ga75RF6isOhn00= +github.com/go-chassis/cari v0.4.1-0.20210528013912-6da8395f7ff9/go.mod h1:av/19fqwEP4eOC8unL/z67AAbFDwXUCko6SKa4Avrd8= github.com/go-chassis/foundation v0.2.2-0.20201210043510-9f6d3de40234/go.mod h1:2PjwqpVwYEVaAldl5A58a08viH8p27pNeYaiE3ZxOBA= github.com/go-chassis/foundation v0.2.2/go.mod h1:2PjwqpVwYEVaAldl5A58a08viH8p27pNeYaiE3ZxOBA= github.com/go-chassis/foundation v0.3.0 h1:jG4BIrK8fXD9jbTtJ5rOLGQZ1pQI/mLnDuVJzToCtos= github.com/go-chassis/foundation v0.3.0/go.mod h1:2PjwqpVwYEVaAldl5A58a08viH8p27pNeYaiE3ZxOBA= +github.com/go-chassis/foundation v0.3.1-0.20210602072914-a580bed505d0 h1:bWvRZc0/sxPjzOBB4DTjxcFjpoy3MdSt5fbIimx2FtE= +github.com/go-chassis/foundation v0.3.1-0.20210602072914-a580bed505d0/go.mod h1:6NsIUaHghTFRGfCBcZN011zl196F6OR5QvD9N+P4oWU= github.com/go-chassis/go-archaius v1.3.6-0.20201210061741-7450779aaeb8/go.mod h1:j8vJX5c455N0cN5rzeC1dm9T5kyOI8ZvIjaSJ+rZjwc= github.com/go-chassis/go-archaius v1.4.0/go.mod h1:j8vJX5c455N0cN5rzeC1dm9T5kyOI8ZvIjaSJ+rZjwc= github.com/go-chassis/go-archaius v1.5.0/go.mod h1:QPwvvtBxvwiC48rmydoAqxopqOr93RCQ6syWsIkXPXQ= @@ -341,6 +347,9 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/karlseguin/ccache v2.0.3-0.20170217060820-3ba9789cfd2c+incompatible/go.mod h1:CM9tNPzT6EdRh14+jiW8mEF9mkNZuuE51qmgGYUB93w= +github.com/karlseguin/ccache/v2 v2.0.8 h1:lT38cE//uyf6KcFok0rlgXtGFBWxkI6h/qg4tbFyDnA= +github.com/karlseguin/ccache/v2 v2.0.8/go.mod h1:2BDThcfQMf/c0jnZowt16eW405XIqZPavt+HoYEtcxQ= +github.com/karlseguin/expect v1.0.2-0.20190806010014-778a5f0c6003/go.mod h1:zNBxMY8P21owkeogJELCLeHIt+voOSduHYTFUbwRAV8= github.com/karlseguin/expect v1.0.7/go.mod h1:lXdI8iGiQhmzpnnmU/EGA60vqKs8NbRNFnhhrJGoD5g= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= github.com/karrick/godirwalk v1.10.3 h1:lOpSw2vJP0y5eLBW906QwKsUK/fe/QDyoqM5rnnuPDY= @@ -402,6 +411,7 @@ github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKju github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0 h1:tEElEatulEHDeedTxwckzyYMA5c86fbmNIUL1hBIiTg= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee h1:kK7VuFVykgt0LfMSloWYjDOt4TnOcL0AxF0/rDq2VkM= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= diff --git a/pkg/model/db_schema.go b/pkg/model/db_schema.go index 8875c24..5583df7 100644 --- a/pkg/model/db_schema.go +++ b/pkg/model/db_schema.go @@ -33,19 +33,19 @@ type LabelDoc struct { type KVDoc struct { ID string `json:"id,omitempty" bson:"id,omitempty" yaml:"id,omitempty" swag:"string"` LabelFormat string `json:"label_format,omitempty" bson:"label_format,omitempty" yaml:"label_format,omitempty"` - Key string `json:"key" yaml:"key" validate:"key"` - Value string `json:"value" yaml:"value" validate:"value"` + Key string `json:"key" yaml:"key" validate:"min=1,max=128,key"` + Value string `json:"value" yaml:"value" validate:"max=2097152,value"` ValueType string `json:"value_type,omitempty" bson:"value_type,omitempty" yaml:"value_type,omitempty" validate:"valueType"` //ini,json,text,yaml,properties - Checker string `json:"check,omitempty" yaml:"check,omitempty" validate:"check"` //python script + Checker string `json:"check,omitempty" yaml:"check,omitempty" validate:"max=1048576,check"` //python script CreateRevision int64 `json:"create_revision,omitempty" bson:"create_revision," yaml:"create_revision,omitempty"` UpdateRevision int64 `json:"update_revision,omitempty" bson:"update_revision," yaml:"update_revision,omitempty"` - Project string `json:"project,omitempty" yaml:"project,omitempty" validate:"commonName"` + Project string `json:"project,omitempty" yaml:"project,omitempty" validate:"min=1,max=256,commonName"` Status string `json:"status,omitempty" yaml:"status,omitempty" validate:"kvStatus"` CreateTime int64 `json:"create_time,omitempty" bson:"create_time," yaml:"create_time,omitempty"` UpdateTime int64 `json:"update_time,omitempty" bson:"update_time," yaml:"update_time,omitempty"` Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty" validate:"max=6,dive,keys,labelKV,endkeys,labelKV"` //redundant - Domain string `json:"domain,omitempty" yaml:"domain,omitempty" validate:"commonName"` //redundant + Domain string `json:"domain,omitempty" yaml:"domain,omitempty" validate:"min=1,max=256,commonName"` //redundant } //ViewDoc is db struct, it saves user's custom view name and criteria @@ -76,24 +76,24 @@ type PollingDetail struct { // UpdateKVRequest is db struct, it contains kv update request params type UpdateKVRequest struct { ID string `json:"id,omitempty" bson:"id,omitempty" yaml:"id,omitempty" swag:"string" validate:"uuid"` - Value string `json:"value,omitempty" yaml:"value,omitempty" validate:"value"` - Project string `json:"project,omitempty" yaml:"project,omitempty" validate:"commonName"` - Domain string `json:"domain,omitempty" yaml:"domain,omitempty" validate:"commonName"` //redundant + Value string `json:"value,omitempty" yaml:"value,omitempty" validate:"max=2097152,value"` + Project string `json:"project,omitempty" yaml:"project,omitempty" validate:"min=1,max=256,commonName"` + Domain string `json:"domain,omitempty" yaml:"domain,omitempty" validate:"min=1,max=256,commonName"` //redundant Status string `json:"status,omitempty" yaml:"status,omitempty" validate:"kvStatus"` } // GetKVRequest contains kv get request params type GetKVRequest struct { - Project string `json:"project,omitempty" yaml:"project,omitempty" validate:"commonName"` - Domain string `json:"domain,omitempty" yaml:"domain,omitempty" validate:"commonName"` //redundant + Project string `json:"project,omitempty" yaml:"project,omitempty" validate:"min=1,max=256,commonName"` + Domain string `json:"domain,omitempty" yaml:"domain,omitempty" validate:"min=1,max=256,commonName"` //redundant ID string `json:"id,omitempty" bson:"id,omitempty" yaml:"id,omitempty" swag:"string" validate:"uuid"` } // ListKVRequest contains kv list request params type ListKVRequest struct { - Project string `json:"project,omitempty" yaml:"project,omitempty" validate:"commonName"` - Domain string `json:"domain,omitempty" yaml:"domain,omitempty" validate:"commonName"` //redundant - Key string `json:"key" yaml:"key" validate:"getKey"` + Project string `json:"project,omitempty" yaml:"project,omitempty" validate:"min=1,max=256,commonName"` + Domain string `json:"domain,omitempty" yaml:"domain,omitempty" validate:"min=1,max=256,commonName"` //redundant + Key string `json:"key" yaml:"key" validate:"max=128,getKey"` Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty" validate:"max=8,dive,keys,labelKV,endkeys,labelKV"` //redundant Offset int64 `validate:"min=0"` Limit int64 `validate:"min=0,max=100"` diff --git a/pkg/validate/instance.go b/pkg/validate/instance.go deleted file mode 100644 index fe1c2ab..0000000 --- a/pkg/validate/instance.go +++ /dev/null @@ -1,49 +0,0 @@ -package validate - -var defaultValidator = NewValidator() - -const ( - key = "key" - commonNameRegexString = `^[a-zA-Z0-9]*$|^[a-zA-Z0-9][a-zA-Z0-9_\-.]*[a-zA-Z0-9]$` - getKeyRegexString = `^[a-zA-Z0-9]*$|^[a-zA-Z0-9][a-zA-Z0-9_\-.]*[a-zA-Z0-9]$|^beginWith\([a-zA-Z0-9][a-zA-Z0-9_\-.]*\)$|^wildcard\([a-zA-Z0-9][a-zA-Z0-9_\-.*]*\)$` - asciiRegexString = `^[\x00-\x7F]*$` - allCharString = `.*` -) - -// custom validate rules -// please use different tag names from third party tags -var customRules = []*RegexValidateRule{ - NewRule(key, commonNameRegexString, &Option{Min: 1, Max: 128}), - NewRule("getKey", getKeyRegexString, &Option{Max: 128}), - NewRule("commonName", commonNameRegexString, &Option{Min: 1, Max: 256}), - NewRule("valueType", `^$|^(ini|json|text|yaml|properties)$`, nil), - NewRule("kvStatus", `^$|^(enabled|disabled)$`, nil), - NewRule("value", allCharString, &Option{Max: 2097152}), //ASCII, 2M - NewRule("labelKV", commonNameRegexString, &Option{Max: 32}), - NewRule("check", asciiRegexString, &Option{Max: 1048576}), //ASCII, 1M -} - -// tags of third party validate rules we used, for error translation -var thirdPartyTags = []string{ - "min", "max", "length", "uuid", -} - -// Init initializes validate -func Init() error { - for _, r := range customRules { - if err := defaultValidator.RegisterRule(r); err != nil { - return err - } - } - for _, t := range thirdPartyTags { - if err := defaultValidator.AddErrorTranslation4Tag(t); err != nil { - return err - } - } - return nil -} - -// Validate validates data -func Validate(v interface{}) error { - return defaultValidator.Validate(v) -} diff --git a/pkg/validate/instance_test.go b/pkg/validate/instance_test.go deleted file mode 100644 index 0519656..0000000 --- a/pkg/validate/instance_test.go +++ /dev/null @@ -1,125 +0,0 @@ -package validate_test - -import ( - "testing" - - "github.com/apache/servicecomb-kie/pkg/model" - "github.com/apache/servicecomb-kie/pkg/validate" - - "github.com/stretchr/testify/assert" -) - -func TestValidate(t *testing.T) { - string32 := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" //32 - string128 := string32 + string32 + string32 + string32 - err := validate.Init() - assert.NoError(t, err) - - kvDoc := &model.KVDoc{Project: "a", Domain: "a", - Key: "a", - Value: "a", - } - assert.NoError(t, validate.Validate(kvDoc)) - - kvDoc = &model.KVDoc{Project: "a", Domain: "a", - Key: "", - Value: "a", - } - assert.Error(t, validate.Validate(kvDoc)) - - kvDoc = &model.KVDoc{Project: "a", Domain: "a", - Key: "a#", - Value: "a", - } - assert.Error(t, validate.Validate(kvDoc)) - - kvDoc = &model.KVDoc{Project: "a", Domain: "a", - Key: string128 + "a", - Value: "a", - } - assert.Error(t, validate.Validate(kvDoc)) - - kvDoc = &model.KVDoc{Project: "a", Domain: "a", - Key: "a", - Value: "", - } - assert.NoError(t, validate.Validate(kvDoc)) - - kvDoc = &model.KVDoc{Project: "a", Domain: "a", - Key: "a", - Value: "a", - ValueType: "", - } - assert.NoError(t, validate.Validate(kvDoc)) - - kvDoc = &model.KVDoc{Project: "a", Domain: "a", - Key: "a", - Value: "a", - ValueType: "text", - } - assert.NoError(t, validate.Validate(kvDoc)) - - kvDoc = &model.KVDoc{Project: "a", Domain: "a", - Key: "a", - Value: "a", - ValueType: "a", - } - assert.Error(t, validate.Validate(kvDoc)) - - kvDoc = &model.KVDoc{Project: "a", Domain: "a", - Key: "a", - Value: "a", - Status: "", - } - assert.NoError(t, validate.Validate(kvDoc)) - - kvDoc = &model.KVDoc{Project: "a", Domain: "a", - Key: "a", - Value: "a", - Status: "enabled", - } - assert.NoError(t, validate.Validate(kvDoc)) - - kvDoc = &model.KVDoc{Project: "a", Domain: "a", - Key: "a", - Value: "a", - Status: "a", - } - assert.Error(t, validate.Validate(kvDoc)) - - kvDoc = &model.KVDoc{Project: "a", Domain: "a", - Key: "a", - Value: "a", - Labels: nil, - } - assert.NoError(t, validate.Validate(kvDoc)) - - kvDoc = &model.KVDoc{Project: "a", Domain: "a", - Key: "a", - Value: "a", - Labels: map[string]string{"a": "a"}, - } - assert.NoError(t, validate.Validate(kvDoc)) - - kvDoc = &model.KVDoc{Project: "a", Domain: "a", - Key: "a", - Value: "a", - Labels: map[string]string{string32 + "a": "a"}, - } - assert.Error(t, validate.Validate(kvDoc)) - - ListKVRe := &model.ListKVRequest{Project: "a", Domain: "a", - Key: "beginWith(a)", - } - assert.NoError(t, validate.Validate(ListKVRe)) - - ListKVRe = &model.ListKVRequest{Project: "a", Domain: "a", - Key: "beginW(a)", - } - assert.Error(t, validate.Validate(ListKVRe)) - - ListKVRe = &model.ListKVRequest{Project: "a", Domain: "a", - Key: "beginW()", - } - assert.Error(t, validate.Validate(ListKVRe)) -} diff --git a/pkg/validate/rule.go b/pkg/validate/rule.go deleted file mode 100644 index 3fb9560..0000000 --- a/pkg/validate/rule.go +++ /dev/null @@ -1,90 +0,0 @@ -package validate - -import ( - "fmt" - "regexp" - "unicode/utf8" - - "github.com/go-playground/validator" -) - -// RegexValidateRule contains an validate tag's info -type RegexValidateRule struct { - tag string - min int64 - max int64 - regex *regexp.Regexp - validateFuncs []func(string) bool -} - -// Option is RegexValidateRule option -type Option struct { - Min int64 - Max int64 -} - -// Validate validates string -func (r *RegexValidateRule) Validate(s string) bool { - for _, f := range r.validateFuncs { - if ok := f(s); !ok { - return false - } - } - return true -} - -func (r *RegexValidateRule) validateFL(fl validator.FieldLevel) bool { - return r.Validate(fl.Field().String()) -} - -// Tag returns the validate rule's tag -func (r *RegexValidateRule) Tag() string { - return r.tag -} - -// Explain explains the rule -func (r *RegexValidateRule) Explain() string { - explain := r.regex.String() - if r.max > 0 { - explain = fmt.Sprintf("%s , max = %d", explain, r.max) - } - if r.min > 0 { - explain = fmt.Sprintf("%s , min = %d", explain, r.min) - } - return explain -} - -func (r *RegexValidateRule) matchRegex(s string) bool { - return r.regex.MatchString(s) -} -func (r *RegexValidateRule) matchMin(s string) bool { - return int64(utf8.RuneCountInString(s)) >= r.min -} -func (r *RegexValidateRule) matchMax(s string) bool { - return int64(utf8.RuneCountInString(s)) <= r.max -} - -// NewRule news a rule -func NewRule(tag, regexStr string, opt *Option) *RegexValidateRule { - r := &RegexValidateRule{ - tag: tag, - regex: regexp.MustCompile(regexStr), - validateFuncs: make([]func(string) bool, 0), - } - - if opt == nil { - r.validateFuncs = append(r.validateFuncs, r.matchRegex) - return r - } - - if opt.Max > 0 { - r.max = opt.Max - r.validateFuncs = append(r.validateFuncs, r.matchMax) - } - if opt.Min > 0 { - r.min = opt.Min - r.validateFuncs = append(r.validateFuncs, r.matchMin) - } - r.validateFuncs = append(r.validateFuncs, r.matchRegex) - return r -} diff --git a/pkg/validate/rule_test.go b/pkg/validate/rule_test.go deleted file mode 100644 index d2336a9..0000000 --- a/pkg/validate/rule_test.go +++ /dev/null @@ -1,39 +0,0 @@ -package validate_test - -import ( - "testing" - - "github.com/apache/servicecomb-kie/pkg/validate" - "github.com/stretchr/testify/assert" -) - -func TestNewRule(t *testing.T) { - rule := validate.NewRule("t", `^[a-zA-Z0-9]*$`, &validate.Option{Min: 2, Max: 4}) - assert.Equal(t, "t", rule.Tag()) - rule.Explain() - assert.True(t, rule.Validate("ab")) - assert.False(t, rule.Validate("a")) - assert.False(t, rule.Validate("abcde")) - assert.False(t, rule.Validate("ab-")) - - rule = validate.NewRule("t", `^[a-zA-Z0-9]*$`, &validate.Option{Min: 2}) - rule.Explain() - assert.True(t, rule.Validate("ab")) - assert.False(t, rule.Validate("a")) - assert.True(t, rule.Validate("abcde")) - assert.False(t, rule.Validate("ab-")) - - rule = validate.NewRule("t", `^[a-zA-Z0-9]*$`, &validate.Option{Max: 4}) - rule.Explain() - assert.True(t, rule.Validate("ab")) - assert.True(t, rule.Validate("a")) - assert.False(t, rule.Validate("abcde")) - assert.False(t, rule.Validate("ab-")) - - rule = validate.NewRule("t", `^[a-zA-Z0-9]*$`, nil) - rule.Explain() - assert.True(t, rule.Validate("ab")) - assert.True(t, rule.Validate("a")) - assert.True(t, rule.Validate("abcdefg12345678")) - assert.False(t, rule.Validate("ab-")) -} diff --git a/pkg/validate/validator.go b/pkg/validate/validator.go deleted file mode 100644 index 59fdf26..0000000 --- a/pkg/validate/validator.go +++ /dev/null @@ -1,87 +0,0 @@ -package validate - -import ( - "errors" - "fmt" - "strings" - - ut "github.com/go-playground/universal-translator" - valid "github.com/go-playground/validator" -) - -var errorTranslator ut.Translator // no use but as an index - -func registerErrorTranslator(_ ut.Translator) error { return nil } - -// Validator validates data -// not safe, use it after initialized -type Validator struct { - rules map[string]*RegexValidateRule - valid *valid.Validate -} - -// Validate validates the input data -func (v *Validator) Validate(i interface{}) error { - err := v.valid.Struct(i) - if err != nil { - return v.wrapError(err) - } - return nil -} - -// converts the raw error into an easy-to-understand error -func (v *Validator) wrapError(err error) error { - validErr, ok := err.(valid.ValidationErrors) - if !ok { - return err - } - msgs := make([]string, len(validErr)) - for i, ve := range validErr { - fe := ve.(valid.FieldError) - msgs[i] = fe.Translate(errorTranslator) - } - return errors.New("validate failed, " + strings.Join(msgs, " | ")) -} - -// RegisterRule registers a custom validate rule -func (v *Validator) RegisterRule(r *RegexValidateRule) error { - if r == nil { - return errors.New("empty regex validate rule") - } - v.rules[r.tag] = r - if err := v.valid.RegisterValidation(r.tag, r.validateFL); err != nil { - return err - } - return v.AddErrorTranslation4Tag(r.tag) -} - -// translates raw errors to easy-to-understand messages -func (v *Validator) translateError(_ ut.Translator, fe valid.FieldError) string { - var rule string - if r, ok := v.rules[fe.Tag()]; ok { - rule = r.Explain() - } else { - rule = fe.Tag() - if len(fe.Param()) > 0 { - rule = rule + " = " + fe.Param() - } - } - return fmt.Sprintf("field: %s, rule: %s", fe.Namespace(), rule) -} - -// AddErrorTranslation4Tag adds translation for the errors of some tag, -// to make the error easier to understand -func (v *Validator) AddErrorTranslation4Tag(tag string) error { - return v.valid.RegisterTranslation(tag, - errorTranslator, - registerErrorTranslator, - v.translateError) -} - -// NewValidator news a validator -func NewValidator() *Validator { - return &Validator{ - valid: valid.New(), - rules: make(map[string]*RegexValidateRule), - } -} diff --git a/pkg/validate/validator_test.go b/pkg/validate/validator_test.go deleted file mode 100644 index 3bcde81..0000000 --- a/pkg/validate/validator_test.go +++ /dev/null @@ -1,36 +0,0 @@ -package validate_test - -import ( - "testing" - - "github.com/apache/servicecomb-kie/pkg/validate" - "github.com/stretchr/testify/assert" -) - -type student struct { - Name string `validate:"kieTest"` - Address string `validate:"alpha,min=2,max=4"` -} - -func TestNewValidator(t *testing.T) { - r := validate.NewRule("kieTest", `^[a-zA-Z0-9]*$`, nil) - valid := validate.NewValidator() - err := valid.RegisterRule(r) - assert.Nil(t, err) - assert.Nil(t, valid.AddErrorTranslation4Tag("min")) - assert.Nil(t, valid.AddErrorTranslation4Tag("max")) - - s := &student{Name: "a1", Address: "abc"} - err = valid.Validate(s) - assert.Nil(t, err) - - s = &student{Name: "a1-", Address: "abc"} - err = valid.Validate(s) - assert.NotNil(t, err) - t.Log(err) - - s = &student{Name: "a1", Address: "abcde"} - err = valid.Validate(s) - assert.NotNil(t, err) - t.Log(err) -} diff --git a/pkg/validator/rule.go b/pkg/validator/rule.go new file mode 100644 index 0000000..b6e9e71 --- /dev/null +++ b/pkg/validator/rule.go @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package validator + +import "github.com/go-chassis/foundation/validator" + +const ( + key = "key" + commonNameRegexString = `^[a-zA-Z0-9]*$|^[a-zA-Z0-9][a-zA-Z0-9_\-.]*[a-zA-Z0-9]$` + labelKvRegexString = `^[a-zA-Z0-9]{0,32}$|^[a-zA-Z0-9][a-zA-Z0-9_\-.]{0,30}[a-zA-Z0-9]$` + getKeyRegexString = `^[a-zA-Z0-9]*$|^[a-zA-Z0-9][a-zA-Z0-9_\-.]*[a-zA-Z0-9]$|^beginWith\([a-zA-Z0-9][a-zA-Z0-9_\-.]*\)$|^wildcard\([a-zA-Z0-9][a-zA-Z0-9_\-.*]*\)$` + asciiRegexString = `^[\x00-\x7F]*$` + allCharString = `.*` +) + +// custom validate rules +// please use different tag names from third party tags +var customRules = []*validator.RegexValidateRule{ + validator.NewRegexRule(key, commonNameRegexString), + validator.NewRegexRule("getKey", getKeyRegexString), + validator.NewRegexRule("commonName", commonNameRegexString), + validator.NewRegexRule("valueType", `^$|^(ini|json|text|yaml|properties)$`), + validator.NewRegexRule("kvStatus", `^$|^(enabled|disabled)$`), + validator.NewRegexRule("value", allCharString), //ASCII, 2M + validator.NewRegexRule("labelKV", labelKvRegexString), + validator.NewRegexRule("check", asciiRegexString), //ASCII, 1M +} + +func Init() error { + return validator.RegisterRegexRules(customRules) +} diff --git a/pkg/validator/rule_test.go b/pkg/validator/rule_test.go new file mode 100644 index 0000000..5cf5705 --- /dev/null +++ b/pkg/validator/rule_test.go @@ -0,0 +1,173 @@ +package validator_test + +import ( + "github.com/go-chassis/foundation/validator" + "strings" + "testing" + + "github.com/apache/servicecomb-kie/pkg/model" + validsvc "github.com/apache/servicecomb-kie/pkg/validator" + "github.com/stretchr/testify/assert" +) + +func init() { + if err := validsvc.Init(); err != nil { + panic(err) + } +} + +func TestValidate(t *testing.T) { + string32 := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" //32 + string128 := string32 + string32 + string32 + string32 + + kvDoc := &model.KVDoc{Project: "a", Domain: "a", + Key: "a", + Value: "a", + } + assert.NoError(t, validator.Validate(kvDoc)) + + kvDoc = &model.KVDoc{Project: "a", Domain: "a", + Key: "", + Value: "a", + } + assert.Error(t, validator.Validate(kvDoc)) + + kvDoc = &model.KVDoc{Project: "a", Domain: "a", + Key: "a#", + Value: "a", + } + assert.Error(t, validator.Validate(kvDoc)) + + kvDoc = &model.KVDoc{Project: "a", Domain: "a", + Key: string128 + "a", + Value: "a", + } + assert.Error(t, validator.Validate(kvDoc)) + + kvDoc = &model.KVDoc{Project: "a", Domain: "a", + Key: "a", + Value: "", + } + assert.NoError(t, validator.Validate(kvDoc)) + + kvDoc = &model.KVDoc{Project: "a", Domain: "a", + Key: "a", + Value: "a", + ValueType: "", + } + assert.NoError(t, validator.Validate(kvDoc)) + + kvDoc = &model.KVDoc{Project: "a", Domain: "a", + Key: "a", + Value: "a", + ValueType: "text", + } + assert.NoError(t, validator.Validate(kvDoc)) + + kvDoc = &model.KVDoc{Project: "a", Domain: "a", + Key: "a", + Value: "a", + ValueType: "a", + } + assert.Error(t, validator.Validate(kvDoc)) + + kvDoc = &model.KVDoc{Project: "a", Domain: "a", + Key: "a", + Value: "a", + Status: "", + } + assert.NoError(t, validator.Validate(kvDoc)) + + kvDoc = &model.KVDoc{Project: "a", Domain: "a", + Key: "a", + Value: "a", + Status: "enabled", + } + assert.NoError(t, validator.Validate(kvDoc)) + + kvDoc = &model.KVDoc{Project: "a", Domain: "a", + Key: "a", + Value: "a", + Status: "a", + } + assert.Error(t, validator.Validate(kvDoc)) + + kvDoc = &model.KVDoc{Project: "a", Domain: "a", + Key: "a", + Value: "a", + Labels: nil, + } + assert.NoError(t, validator.Validate(kvDoc)) + + kvDoc = &model.KVDoc{Project: "a", Domain: "a", + Key: "a", + Value: "a", + Labels: map[string]string{"a": "a"}, + } + assert.NoError(t, validator.Validate(kvDoc)) + + kvDoc = &model.KVDoc{Project: "a", Domain: "a", + Key: "a", + Value: "a", + Labels: map[string]string{ + "1": "a", + "2": "a", + "3": "a", + "4": "a", + "5": "a", + "6": "a", + "7": "a", // error + }, + } + assert.Error(t, validator.Validate(kvDoc)) + + kvDoc = &model.KVDoc{Project: "a", Domain: "a", + Key: "a", + Value: "a", + Labels: map[string]string{ + "1": "a", + "2": "a", + "3": "a", + "4": "a", + "5": "a", + "6-" + strings.Repeat("x", 31): "a", // error + }, + } + assert.Error(t, validator.Validate(kvDoc)) + + kvDoc = &model.KVDoc{Project: "a", Domain: "a", + Key: "a", + Value: "a", + Labels: map[string]string{ + "1": "a", + "2": "a", + "3": "a", + "4": "a", + "5": "a", + "6": "a-" + strings.Repeat("x", 31), // error + }, + } + assert.Error(t, validator.Validate(kvDoc)) + + kvDoc = &model.KVDoc{Project: "a", Domain: "a", + Key: "a", + Value: "a", + Labels: map[string]string{string32 + "a": "a"}, + } + assert.Error(t, validator.Validate(kvDoc)) + + ListKVRe := &model.ListKVRequest{Project: "a", Domain: "a", + Key: "beginWith(a)", + } + assert.NoError(t, validator.Validate(ListKVRe)) + + ListKVRe = &model.ListKVRequest{Project: "a", Domain: "a", + Key: "beginW(a)", + } + assert.Error(t, validator.Validate(ListKVRe)) + + ListKVRe = &model.ListKVRequest{Project: "a", Domain: "a", + Key: "beginW()", + } + assert.Error(t, validator.Validate(ListKVRe)) +} diff --git a/server/resource/v1/kv_resource.go b/server/resource/v1/kv_resource.go index b228e3a..51f74be 100644 --- a/server/resource/v1/kv_resource.go +++ b/server/resource/v1/kv_resource.go @@ -21,11 +21,11 @@ package v1 import ( "encoding/json" "fmt" + "github.com/go-chassis/foundation/validator" "net/http" "github.com/apache/servicecomb-kie/pkg/common" "github.com/apache/servicecomb-kie/pkg/model" - "github.com/apache/servicecomb-kie/pkg/validate" "github.com/apache/servicecomb-kie/server/pubsub" "github.com/apache/servicecomb-kie/server/service" "github.com/apache/servicecomb-kie/server/service/mongo/session" @@ -55,7 +55,7 @@ func (r *KVResource) Post(rctx *restful.Context) { if kv.Status == "" { kv.Status = common.StatusDisabled } - err = validate.Validate(kv) + err = validator.Validate(kv) if err != nil { WriteErrResponse(rctx, http.StatusBadRequest, err.Error()) return @@ -114,7 +114,7 @@ func (r *KVResource) Put(rctx *restful.Context) { kvReq.ID = kvID kvReq.Domain = domain kvReq.Project = project - err = validate.Validate(kvReq) + err = validator.Validate(kvReq) if err != nil { WriteErrResponse(rctx, http.StatusBadRequest, err.Error()) return @@ -151,7 +151,7 @@ func (r *KVResource) Get(rctx *restful.Context) { Domain: ReadDomain(rctx.Ctx), ID: rctx.ReadPathParameter(common.PathParamKVID), } - err := validate.Validate(request) + err := validator.Validate(request) if err != nil { WriteErrResponse(rctx, http.StatusBadRequest, err.Error()) return @@ -198,7 +198,7 @@ func (r *KVResource) List(rctx *restful.Context) { } request.Offset = offset request.Limit = limit - err = validate.Validate(request) + err = validator.Validate(request) if err != nil { WriteErrResponse(rctx, http.StatusBadRequest, err.Error()) return diff --git a/server/resource/v1/kv_resource_test.go b/server/resource/v1/kv_resource_test.go index 7402427..b7d6f5e 100644 --- a/server/resource/v1/kv_resource_test.go +++ b/server/resource/v1/kv_resource_test.go @@ -22,7 +22,6 @@ import ( "encoding/json" common2 "github.com/apache/servicecomb-kie/pkg/common" "github.com/apache/servicecomb-kie/pkg/model" - "github.com/apache/servicecomb-kie/pkg/validate" "github.com/apache/servicecomb-kie/server/config" "github.com/apache/servicecomb-kie/server/plugin/qms" "github.com/apache/servicecomb-kie/server/pubsub" @@ -47,9 +46,6 @@ import ( ) func init() { - if err := validate.Init(); err != nil { - panic(err) - } log.Init(log.Config{ Writers: []string{"stdout"}, LoggerLevel: "DEBUG", diff --git a/server/server.go b/server/server.go index 3f57559..93215ab 100644 --- a/server/server.go +++ b/server/server.go @@ -18,7 +18,7 @@ package server import ( - "github.com/apache/servicecomb-kie/pkg/validate" + "github.com/apache/servicecomb-kie/pkg/validator" "github.com/apache/servicecomb-kie/server/config" "github.com/apache/servicecomb-kie/server/pubsub" "github.com/apache/servicecomb-kie/server/rbac" @@ -42,7 +42,7 @@ func Run() { if err := service.DBInit(); err != nil { openlog.Fatal(err.Error()) } - if err := validate.Init(); err != nil { + if err := validator.Init(); err != nil { openlog.Fatal("validate init failed: " + err.Error()) } rbac.Init() diff --git a/test/init.go b/test/init.go index 9841401..397c104 100644 --- a/test/init.go +++ b/test/init.go @@ -18,6 +18,7 @@ package test import ( + "github.com/apache/servicecomb-kie/pkg/validator" "github.com/go-chassis/go-archaius" "github.com/go-chassis/go-chassis/v2/security/cipher" _ "github.com/go-chassis/go-chassis/v2/security/cipher/plugins/plain" @@ -27,4 +28,5 @@ func init() { archaius.Init(archaius.WithMemorySource()) archaius.Set("servicecomb.cipher.plugin", "default") cipher.Init() + validator.Init() }