mirror of
https://github.com/versia-pub/versia-go.git
synced 2025-12-06 22:38:20 +01:00
142 lines
3.8 KiB
Go
142 lines
3.8 KiB
Go
package val_impls
|
|
|
|
import (
|
|
"errors"
|
|
"github.com/versia-pub/versia-go/ent/schema"
|
|
"github.com/versia-pub/versia-go/internal/validators"
|
|
"reflect"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/go-logr/logr"
|
|
en_locale "github.com/go-playground/locales/en"
|
|
universal_translator "github.com/go-playground/universal-translator"
|
|
"github.com/go-playground/validator/v10"
|
|
en_translations "github.com/go-playground/validator/v10/translations/en"
|
|
"github.com/versia-pub/versia-go/internal/api_schema"
|
|
)
|
|
|
|
type bodyValidator struct {
|
|
Translated string
|
|
Validate func(fl validator.FieldLevel) bool
|
|
}
|
|
|
|
var (
|
|
_ validators.BodyValidator = (*BodyValidatorImpl)(nil)
|
|
|
|
fullUserRegex = regexp.MustCompile("^@([a-z0-9_-]+)(?:@([a-zA-Z0-1-_.]+\\.[a-zA-Z0-9-z]+(?::[0-9]+)?))?$")
|
|
domainRegex = regexp.MustCompile("^[a-zA-Z0-9-_.]+.[a-zA-Z0-9-z]+(?::[0-9]+)?$")
|
|
)
|
|
|
|
type BodyValidatorImpl struct {
|
|
validator *validator.Validate
|
|
translator *universal_translator.UniversalTranslator
|
|
enTranslator universal_translator.Translator
|
|
|
|
log logr.Logger
|
|
}
|
|
|
|
func NewBodyValidator(log logr.Logger) *BodyValidatorImpl {
|
|
en := en_locale.New()
|
|
translator := universal_translator.New(en, en)
|
|
enTranslator, ok := translator.GetTranslator("en")
|
|
if !ok {
|
|
panic("failed to get \"en\" translator")
|
|
}
|
|
|
|
validate := validator.New(validator.WithRequiredStructEnabled())
|
|
if err := en_translations.RegisterDefaultTranslations(validate, enTranslator); err != nil {
|
|
panic("failed to register default translations")
|
|
}
|
|
|
|
validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
|
|
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
|
|
if name == "-" {
|
|
return ""
|
|
}
|
|
return name
|
|
})
|
|
|
|
bodyValidators := map[string]bodyValidator{
|
|
"username_regex": {
|
|
Translated: "{0} must match '^[a-z0-9_-]+$'!",
|
|
Validate: func(fl validator.FieldLevel) bool {
|
|
return schema.ValidateUsername(fl.Field().String()) == nil
|
|
},
|
|
},
|
|
"full_user_regex": {
|
|
Translated: "{0} must match '^@[a-z0-9_-]+$' or '^@[a-z0-9_-]+@[a-zA-Z0-1-_.]+\\.[a-zA-Z0-9-z]+(?::[0-9]+)?))?$'",
|
|
Validate: func(fl validator.FieldLevel) bool {
|
|
f := fl.Field()
|
|
if f.Type().String() == "string" {
|
|
return fullUserRegex.Match([]byte(f.String()))
|
|
}
|
|
|
|
return false
|
|
},
|
|
},
|
|
"domain_regex": {
|
|
Translated: "{0} must match '^[a-zA-Z0-9-_.]+.[a-zA-Z0-9-z]+(?::[0-9]+)?$'",
|
|
Validate: func(fl validator.FieldLevel) bool {
|
|
f := fl.Field()
|
|
t := f.Type().String()
|
|
if t == "string" {
|
|
return domainRegex.Match([]byte(f.String()))
|
|
}
|
|
|
|
log.V(-1).Info("got wrong type: %s\n", t)
|
|
|
|
return false
|
|
},
|
|
},
|
|
}
|
|
|
|
for identifier, v := range bodyValidators {
|
|
if err := validate.RegisterValidation(identifier, v.Validate); err != nil {
|
|
log.Error(err, "failed to register validator", "identifier", identifier)
|
|
}
|
|
|
|
register := func(ut universal_translator.Translator) error {
|
|
return enTranslator.Add(identifier, v.Translated, true)
|
|
}
|
|
|
|
translate := func(ut universal_translator.Translator, fe validator.FieldError) string {
|
|
t, _ := ut.T(identifier, fe.Field())
|
|
return t
|
|
}
|
|
|
|
if err := validate.RegisterTranslation(identifier, enTranslator, register, translate); err != nil {
|
|
log.Error(err, "failed to register validator translator", "identifier", identifier)
|
|
}
|
|
}
|
|
|
|
return &BodyValidatorImpl{
|
|
validator: validate,
|
|
translator: translator,
|
|
enTranslator: enTranslator,
|
|
|
|
log: log,
|
|
}
|
|
}
|
|
|
|
func (i BodyValidatorImpl) Validate(v any) error {
|
|
err := i.validator.Struct(v)
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
|
|
var invalidValidationError *validator.InvalidValidationError
|
|
if errors.As(err, &invalidValidationError) {
|
|
panic(invalidValidationError)
|
|
}
|
|
|
|
i.log.Error(err, "Failed to validate object")
|
|
|
|
errs := make([]string, 0)
|
|
for _, err := range err.(validator.ValidationErrors) {
|
|
errs = append(errs, err.Translate(i.enTranslator))
|
|
}
|
|
|
|
return api_schema.ErrBadRequest(map[string]any{"validation": errs})
|
|
}
|