github.com/angenalZZZ/gofunc@v0.0.0-20210507121333-48ff1be3917b/f/validator.go (about) 1 package f 2 3 import ( 4 "fmt" 5 "reflect" 6 "regexp" 7 "sort" 8 "strconv" 9 "strings" 10 ) 11 12 const maxURLRuneCount = 2083 13 const minURLRuneCount = 3 14 const RF3339WithoutZone = "2006-01-02T15:04:05" 15 16 var ( 17 fieldsRequiredByDefault bool 18 nilPtrAllowedByRequired = false 19 notNumberRegexp = regexp.MustCompile("[^0-9]+") 20 whiteSpacesAndMinus = regexp.MustCompile(`[\s-]+`) 21 paramsRegexp = regexp.MustCompile(`\(.*\)$`) 22 ) 23 24 // ValidateMap use validation map for fields. 25 // result will be equal to `false` if there are any errors. 26 // m is the validation map in the form 27 // map[string]interface{}{"name":"required,alpha","address":map[string]interface{}{"line1":"required,alphanum"}} 28 func ValidateMap(s map[string]interface{}, m map[string]interface{}) (bool, error) { 29 if s == nil { 30 return true, nil 31 } 32 result := true 33 var err error 34 var errs Errors 35 var index int 36 val := reflect.ValueOf(s) 37 for key, value := range s { 38 presentResult := true 39 validator, ok := m[key] 40 if !ok { 41 presentResult = false 42 var err error 43 err = fmt.Errorf("all map keys has to be present in the validation map; got %s", key) 44 err = PrependPathToErrors(err, key) 45 errs = append(errs, err) 46 } 47 valueField := reflect.ValueOf(value) 48 mapResult := true 49 typeResult := true 50 structResult := true 51 resultField := true 52 switch subValidator := validator.(type) { 53 case map[string]interface{}: 54 var err error 55 if v, ok := value.(map[string]interface{}); !ok { 56 mapResult = false 57 err = fmt.Errorf("map validator has to be for the map type only; got %s", valueField.Type().String()) 58 err = PrependPathToErrors(err, key) 59 errs = append(errs, err) 60 } else { 61 mapResult, err = ValidateMap(v, subValidator) 62 if err != nil { 63 mapResult = false 64 err = PrependPathToErrors(err, key) 65 errs = append(errs, err) 66 } 67 } 68 case string: 69 if (valueField.Kind() == reflect.Struct || 70 (valueField.Kind() == reflect.Ptr && valueField.Elem().Kind() == reflect.Struct)) && 71 subValidator != "-" { 72 var err error 73 structResult, err = ValidateStruct(valueField.Interface()) 74 if err != nil { 75 err = PrependPathToErrors(err, key) 76 errs = append(errs, err) 77 } 78 } 79 resultField, err = typeCheck(valueField, reflect.StructField{ 80 Name: key, 81 PkgPath: "", 82 Type: val.Type(), 83 Tag: reflect.StructTag(fmt.Sprintf("%s:%q", RxTagName, subValidator)), 84 Offset: 0, 85 Index: []int{index}, 86 Anonymous: false, 87 }, val, nil) 88 if err != nil { 89 errs = append(errs, err) 90 } 91 case nil: 92 // already handlerd when checked before 93 default: 94 typeResult = false 95 err = fmt.Errorf("map validator has to be either map[string]interface{} or string; got %s", valueField.Type().String()) 96 err = PrependPathToErrors(err, key) 97 errs = append(errs, err) 98 } 99 result = result && presentResult && typeResult && resultField && structResult && mapResult 100 index++ 101 } 102 // check required keys 103 requiredResult := true 104 for key, value := range m { 105 if schema, ok := value.(string); ok { 106 tags := parseTagIntoMap(schema) 107 if required, ok := tags["required"]; ok { 108 if _, ok := s[key]; !ok { 109 requiredResult = false 110 if required.customErrorMessage != "" { 111 err = Error{key, fmt.Errorf(required.customErrorMessage), true, "required", []string{}} 112 } else { 113 err = Error{key, fmt.Errorf("required field missing"), false, "required", []string{}} 114 } 115 errs = append(errs, err) 116 } 117 } 118 } 119 } 120 121 if len(errs) > 0 { 122 err = errs 123 } 124 return result && requiredResult, err 125 } 126 127 // ValidateStruct use tags for fields. 128 // result will be equal to `false` if there are any errors. 129 // to-do currently there is no guarantee that errors will be returned in predictable order (tests may to fail) 130 func ValidateStruct(s interface{}) (bool, error) { 131 if s == nil { 132 return true, nil 133 } 134 result := true 135 var err error 136 val := reflect.ValueOf(s) 137 if val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr { 138 val = val.Elem() 139 } 140 // we only accept structs 141 if val.Kind() != reflect.Struct { 142 return false, fmt.Errorf("function only accepts structs; got %s", val.Kind()) 143 } 144 var errs Errors 145 for i := 0; i < val.NumField(); i++ { 146 valueField := val.Field(i) 147 typeField := val.Type().Field(i) 148 if typeField.PkgPath != "" { 149 continue // Private field 150 } 151 structResult := true 152 if valueField.Kind() == reflect.Interface { 153 valueField = valueField.Elem() 154 } 155 if (valueField.Kind() == reflect.Struct || 156 (valueField.Kind() == reflect.Ptr && valueField.Elem().Kind() == reflect.Struct)) && 157 typeField.Tag.Get(RxTagName) != "-" { 158 var err error 159 structResult, err = ValidateStruct(valueField.Interface()) 160 if err != nil { 161 err = PrependPathToErrors(err, typeField.Name) 162 errs = append(errs, err) 163 } 164 } 165 resultField, err2 := typeCheck(valueField, typeField, val, nil) 166 if err2 != nil { 167 168 // Replace structure name with JSON name if there is a tag on the variable 169 jsonTag := toJSONName(typeField.Tag.Get("json")) 170 if jsonTag != "" { 171 switch jsonError := err2.(type) { 172 case Error: 173 jsonError.Name = jsonTag 174 err2 = jsonError 175 case Errors: 176 for i2, err3 := range jsonError { 177 switch customErr := err3.(type) { 178 case Error: 179 customErr.Name = jsonTag 180 jsonError[i2] = customErr 181 } 182 } 183 184 err2 = jsonError 185 } 186 } 187 188 errs = append(errs, err2) 189 } 190 result = result && resultField && structResult 191 } 192 if len(errs) > 0 { 193 err = errs 194 } 195 return result, err 196 } 197 198 // parseTagIntoMap parses a struct tag `valid:required~Some error message,length(2|3)` into map[string]string{"required": "Some error message", "length(2|3)": ""} 199 func parseTagIntoMap(tag string) tagOptionsMap { 200 optionsMap := make(tagOptionsMap) 201 options := strings.Split(tag, ",") 202 203 for i, option := range options { 204 option = strings.TrimSpace(option) 205 206 validationOptions := strings.Split(option, "~") 207 if !isValidTag(validationOptions[0]) { 208 continue 209 } 210 if len(validationOptions) == 2 { 211 optionsMap[validationOptions[0]] = tagOption{validationOptions[0], validationOptions[1], i} 212 } else { 213 optionsMap[validationOptions[0]] = tagOption{validationOptions[0], "", i} 214 } 215 } 216 return optionsMap 217 } 218 219 func checkRequired(v reflect.Value, t reflect.StructField, options tagOptionsMap) (bool, error) { 220 if nilPtrAllowedByRequired { 221 k := v.Kind() 222 if (k == reflect.Ptr || k == reflect.Interface) && v.IsNil() { 223 return true, nil 224 } 225 } 226 227 if requiredOption, isRequired := options["required"]; isRequired { 228 if len(requiredOption.customErrorMessage) > 0 { 229 return false, Error{t.Name, fmt.Errorf(requiredOption.customErrorMessage), true, "required", []string{}} 230 } 231 return false, Error{t.Name, fmt.Errorf("non zero value required"), false, "required", []string{}} 232 } else if _, isOptional := options["optional"]; fieldsRequiredByDefault && !isOptional { 233 return false, Error{t.Name, fmt.Errorf("Missing required field"), false, "required", []string{}} 234 } 235 // not required and empty is valid 236 return true, nil 237 } 238 239 func typeCheck(v reflect.Value, t reflect.StructField, o reflect.Value, options tagOptionsMap) (isValid bool, resultErr error) { 240 if !v.IsValid() { 241 return false, nil 242 } 243 244 tag := t.Tag.Get(RxTagName) 245 246 // Check if the field should be ignored 247 switch tag { 248 case "": 249 if v.Kind() != reflect.Slice && v.Kind() != reflect.Map { 250 if !fieldsRequiredByDefault { 251 return true, nil 252 } 253 return false, Error{t.Name, fmt.Errorf("All fields are required to at least have one validation defined"), false, "required", []string{}} 254 } 255 case "-": 256 return true, nil 257 } 258 259 isRootType := false 260 if options == nil { 261 isRootType = true 262 options = parseTagIntoMap(tag) 263 } 264 265 if !isFieldSet(v) { 266 // an empty value is not validated, check only required 267 isValid, resultErr = checkRequired(v, t, options) 268 for key := range options { 269 delete(options, key) 270 } 271 return isValid, resultErr 272 } 273 274 var customTypeErrors Errors 275 optionsOrder := options.orderedKeys() 276 for _, validatorName := range optionsOrder { 277 validatorStruct := options[validatorName] 278 if validatefunc, ok := CustomTypeTagMap.Get(validatorName); ok { 279 delete(options, validatorName) 280 281 if result := validatefunc(v.Interface(), o.Interface()); !result { 282 if len(validatorStruct.customErrorMessage) > 0 { 283 customTypeErrors = append(customTypeErrors, Error{Name: t.Name, Err: TruncatingErrorf(validatorStruct.customErrorMessage, fmt.Sprint(v), validatorName), CustomErrorMessageExists: true, Validator: stripParams(validatorName)}) 284 continue 285 } 286 customTypeErrors = append(customTypeErrors, Error{Name: t.Name, Err: fmt.Errorf("%s does not validate as %s", fmt.Sprint(v), validatorName), CustomErrorMessageExists: false, Validator: stripParams(validatorName)}) 287 } 288 } 289 } 290 291 if customTypeErrors != nil && len(customTypeErrors.Errors()) > 0 { 292 return false, customTypeErrors 293 } 294 295 if isRootType { 296 // Ensure that we've checked the value by all specified validators before report that the value is valid 297 defer func() { 298 delete(options, "optional") 299 delete(options, "required") 300 301 if isValid && resultErr == nil && len(options) != 0 { 302 optionsOrder := options.orderedKeys() 303 for _, validator := range optionsOrder { 304 isValid = false 305 resultErr = Error{t.Name, fmt.Errorf( 306 "the following validator is invalid or can't be applied to the field: %q", validator), false, stripParams(validator), []string{}} 307 return 308 } 309 } 310 }() 311 } 312 313 for _, validatorSpec := range optionsOrder { 314 validatorStruct := options[validatorSpec] 315 var negate bool 316 validator := validatorSpec 317 customMsgExists := len(validatorStruct.customErrorMessage) > 0 318 319 // Check whether the tag looks like '!something' or 'something' 320 if validator[0] == '!' { 321 validator = validator[1:] 322 negate = true 323 } 324 325 // Check for interface param validators 326 for key, value := range InterfaceParamTagRegexMap { 327 ps := value.FindStringSubmatch(validator) 328 if len(ps) == 0 { 329 continue 330 } 331 332 validatefunc, ok := InterfaceParamTagMap[key] 333 if !ok { 334 continue 335 } 336 337 delete(options, validatorSpec) 338 339 field := fmt.Sprint(v) 340 if result := validatefunc(v.Interface(), ps[1:]...); (!result && !negate) || (result && negate) { 341 if customMsgExists { 342 return false, Error{t.Name, TruncatingErrorf(validatorStruct.customErrorMessage, field, validator), customMsgExists, stripParams(validatorSpec), []string{}} 343 } 344 if negate { 345 return false, Error{t.Name, fmt.Errorf("%s does validate as %s", field, validator), customMsgExists, stripParams(validatorSpec), []string{}} 346 } 347 return false, Error{t.Name, fmt.Errorf("%s does not validate as %s", field, validator), customMsgExists, stripParams(validatorSpec), []string{}} 348 } 349 } 350 } 351 352 switch v.Kind() { 353 case reflect.Bool, 354 reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 355 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, 356 reflect.Float32, reflect.Float64, 357 reflect.String: 358 // for each tag option check the map of validator functions 359 for _, validatorSpec := range optionsOrder { 360 validatorStruct := options[validatorSpec] 361 var negate bool 362 validator := validatorSpec 363 customMsgExists := len(validatorStruct.customErrorMessage) > 0 364 365 // Check whether the tag looks like '!something' or 'something' 366 if validator[0] == '!' { 367 validator = validator[1:] 368 negate = true 369 } 370 371 // Check for param validators 372 for key, value := range ParamTagRegexMap { 373 ps := value.FindStringSubmatch(validator) 374 if len(ps) == 0 { 375 continue 376 } 377 378 validatefunc, ok := ParamTagMap[key] 379 if !ok { 380 continue 381 } 382 383 delete(options, validatorSpec) 384 385 switch v.Kind() { 386 case reflect.String, 387 reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 388 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, 389 reflect.Float32, reflect.Float64: 390 391 field := fmt.Sprint(v) // make value into string, then validate with regex 392 if result := validatefunc(field, ps[1:]...); (!result && !negate) || (result && negate) { 393 if customMsgExists { 394 return false, Error{t.Name, TruncatingErrorf(validatorStruct.customErrorMessage, field, validator), customMsgExists, stripParams(validatorSpec), []string{}} 395 } 396 if negate { 397 return false, Error{t.Name, fmt.Errorf("%s does validate as %s", field, validator), customMsgExists, stripParams(validatorSpec), []string{}} 398 } 399 return false, Error{t.Name, fmt.Errorf("%s does not validate as %s", field, validator), customMsgExists, stripParams(validatorSpec), []string{}} 400 } 401 default: 402 // type not yet supported, fail 403 return false, Error{t.Name, fmt.Errorf("validator %s doesn't support kind %s", validator, v.Kind()), false, stripParams(validatorSpec), []string{}} 404 } 405 } 406 407 if validatefunc, ok := TagMap[validator]; ok { 408 delete(options, validatorSpec) 409 410 switch v.Kind() { 411 case reflect.String, 412 reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 413 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, 414 reflect.Float32, reflect.Float64: 415 field := fmt.Sprint(v) // make value into string, then validate with regex 416 if result := validatefunc(field); !result && !negate || result && negate { 417 if customMsgExists { 418 return false, Error{t.Name, TruncatingErrorf(validatorStruct.customErrorMessage, field, validator), customMsgExists, stripParams(validatorSpec), []string{}} 419 } 420 if negate { 421 return false, Error{t.Name, fmt.Errorf("%s does validate as %s", field, validator), customMsgExists, stripParams(validatorSpec), []string{}} 422 } 423 return false, Error{t.Name, fmt.Errorf("%s does not validate as %s", field, validator), customMsgExists, stripParams(validatorSpec), []string{}} 424 } 425 default: 426 //Not Yet Supported Types (Fail here!) 427 err := fmt.Errorf("validator %s doesn't support kind %s for value %v", validator, v.Kind(), v) 428 return false, Error{t.Name, err, false, stripParams(validatorSpec), []string{}} 429 } 430 } 431 } 432 return true, nil 433 case reflect.Map: 434 if v.Type().Key().Kind() != reflect.String { 435 return false, &UnsupportedTypeError{v.Type()} 436 } 437 var sv stringValues 438 sv = v.MapKeys() 439 sort.Sort(sv) 440 result := true 441 for i, k := range sv { 442 var resultItem bool 443 var err error 444 if v.MapIndex(k).Kind() != reflect.Struct { 445 resultItem, err = typeCheck(v.MapIndex(k), t, o, options) 446 if err != nil { 447 return false, err 448 } 449 } else { 450 resultItem, err = ValidateStruct(v.MapIndex(k).Interface()) 451 if err != nil { 452 err = PrependPathToErrors(err, t.Name+"."+sv[i].Interface().(string)) 453 return false, err 454 } 455 } 456 result = result && resultItem 457 } 458 return result, nil 459 case reflect.Slice, reflect.Array: 460 result := true 461 for i := 0; i < v.Len(); i++ { 462 var resultItem bool 463 var err error 464 if v.Index(i).Kind() != reflect.Struct { 465 resultItem, err = typeCheck(v.Index(i), t, o, options) 466 if err != nil { 467 return false, err 468 } 469 } else { 470 resultItem, err = ValidateStruct(v.Index(i).Interface()) 471 if err != nil { 472 err = PrependPathToErrors(err, t.Name+"."+strconv.Itoa(i)) 473 return false, err 474 } 475 } 476 result = result && resultItem 477 } 478 return result, nil 479 case reflect.Interface: 480 // If the value is an interface then encode its element 481 if v.IsNil() { 482 return true, nil 483 } 484 return ValidateStruct(v.Interface()) 485 case reflect.Ptr: 486 // If the value is a pointer then check its element 487 if v.IsNil() { 488 return true, nil 489 } 490 return typeCheck(v.Elem(), t, o, options) 491 case reflect.Struct: 492 return true, nil 493 default: 494 return false, &UnsupportedTypeError{v.Type()} 495 } 496 } 497 498 func stripParams(validatorString string) string { 499 return paramsRegexp.ReplaceAllString(validatorString, "") 500 } 501 502 // isFieldSet returns false for nil pointers, interfaces, maps, and slices. For all other values, it returns true. 503 func isFieldSet(v reflect.Value) bool { 504 switch v.Kind() { 505 case reflect.Map, reflect.Slice, reflect.Interface, reflect.Ptr: 506 return !v.IsNil() 507 } 508 509 return true 510 } 511 512 // ErrorByField returns error for specified field of the struct 513 // validated by ValidateStruct or empty string if there are no errors 514 // or this field doesn't exists or doesn't have any errors. 515 func ErrorByField(e error, field string) string { 516 if e == nil { 517 return "" 518 } 519 return ErrorsByField(e)[field] 520 } 521 522 // ErrorsByField returns map of errors of the struct validated 523 // by ValidateStruct or empty map if there are no errors. 524 func ErrorsByField(e error) map[string]string { 525 m := make(map[string]string) 526 if e == nil { 527 return m 528 } 529 // prototype for ValidateStruct 530 531 switch e.(type) { 532 case Error: 533 m[e.(Error).Name] = e.(Error).Err.Error() 534 case Errors: 535 for _, item := range e.(Errors).Errors() { 536 n := ErrorsByField(item) 537 for k, v := range n { 538 m[k] = v 539 } 540 } 541 } 542 543 return m 544 } 545 546 // Error returns string equivalent for reflect.Type 547 func (e *UnsupportedTypeError) Error() string { 548 return "validator: unsupported type: " + e.Type.String() 549 } 550 551 func (sv stringValues) Len() int { return len(sv) } 552 func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] } 553 func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) } 554 func (sv stringValues) get(i int) string { return sv[i].String() } 555 556 // SetFieldsRequiredByDefault causes validation to fail when struct fields 557 // do not include validations or are not explicitly marked as exempt (using `valid:"-"` or `valid:"email,optional"`). 558 // This struct definition will fail govalidator.ValidateStruct() (and the field values do not matter): 559 // type exampleStruct struct { 560 // Name string `` 561 // Email string `valid:"email"` 562 // This, however, will only fail when Email is empty or an invalid email address: 563 // type exampleStruct2 struct { 564 // Name string `valid:"-"` 565 // Email string `valid:"email"` 566 // Lastly, this will only fail when Email is an invalid email address but not when it's empty: 567 // type exampleStruct2 struct { 568 // Name string `valid:"-"` 569 // Email string `valid:"email,optional"` 570 func SetFieldsRequiredByDefault(value bool) { 571 fieldsRequiredByDefault = value 572 } 573 574 // SetNilPtrAllowedByRequired causes validation to pass for nil ptrs when a field is set to required. 575 // The validation will still reject ptr fields in their zero value state. Example with this enabled: 576 // type exampleStruct struct { 577 // Name *string `valid:"required"` 578 // With `Name` set to "", this will be considered invalid input and will cause a validation error. 579 // With `Name` set to nil, this will be considered valid by validation. 580 // By default this is disabled. 581 func SetNilPtrAllowedByRequired(value bool) { 582 nilPtrAllowedByRequired = value 583 }