Files
smart-search-back/pkg/validation/validation.go
vallyenfail 8b9554720d
All checks were successful
Deploy Smart Search Backend / deploy (push) Successful in 1m47s
add service
2026-01-20 19:02:06 +03:00

157 lines
3.7 KiB
Go

package validation
import (
"net/mail"
"regexp"
"strings"
"unicode"
"git.techease.ru/Smart-search/smart-search-back/pkg/errors"
)
const (
MinPasswordLength = 8
MaxPasswordLength = 128
MaxEmailLength = 254
MaxNameLength = 100
MaxPhoneLength = 20
MaxRequestTxtLen = 50000
MaxFileSizeBytes = 10 * 1024 * 1024
)
var (
phoneRegex = regexp.MustCompile(`^\+?[1-9]\d{6,14}$`)
)
func ValidateEmail(email string) error {
if email == "" {
return errors.NewBusinessError(errors.ValidationInvalidEmail, "email is required")
}
if len(email) > MaxEmailLength {
return errors.NewBusinessError(errors.ValidationInvalidEmail, "email is too long")
}
_, err := mail.ParseAddress(email)
if err != nil {
return errors.NewBusinessError(errors.ValidationInvalidEmail, "invalid email format")
}
parts := strings.Split(email, "@")
if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
return errors.NewBusinessError(errors.ValidationInvalidEmail, "invalid email format")
}
if strings.Contains(parts[1], "..") {
return errors.NewBusinessError(errors.ValidationInvalidEmail, "invalid email format")
}
return nil
}
func ValidatePassword(password string) error {
if password == "" {
return errors.NewBusinessError(errors.ValidationInvalidPassword, "password is required")
}
if len(password) < MinPasswordLength {
return errors.NewBusinessError(errors.ValidationInvalidPassword, "password must be at least 8 characters")
}
if len(password) > MaxPasswordLength {
return errors.NewBusinessError(errors.ValidationInvalidPassword, "password is too long")
}
var hasUpper, hasLower, hasDigit bool
for _, c := range password {
switch {
case unicode.IsUpper(c):
hasUpper = true
case unicode.IsLower(c):
hasLower = true
case unicode.IsDigit(c):
hasDigit = true
}
}
if !hasUpper || !hasLower || !hasDigit {
return errors.NewBusinessError(errors.ValidationInvalidPassword, "password must contain uppercase, lowercase and digit")
}
return nil
}
func ValidatePhone(phone string) error {
if phone == "" {
return errors.NewBusinessError(errors.ValidationInvalidPhone, "phone is required")
}
if len(phone) > MaxPhoneLength {
return errors.NewBusinessError(errors.ValidationInvalidPhone, "phone is too long")
}
cleaned := strings.ReplaceAll(phone, " ", "")
cleaned = strings.ReplaceAll(cleaned, "-", "")
cleaned = strings.ReplaceAll(cleaned, "(", "")
cleaned = strings.ReplaceAll(cleaned, ")", "")
if !phoneRegex.MatchString(cleaned) {
return errors.NewBusinessError(errors.ValidationInvalidPhone, "invalid phone format")
}
return nil
}
func ValidateName(name string) error {
if name == "" {
return errors.NewBusinessError(errors.ValidationInvalidName, "name is required")
}
if len(name) > MaxNameLength {
return errors.NewBusinessError(errors.ValidationInvalidName, "name is too long")
}
trimmed := strings.TrimSpace(name)
if trimmed == "" {
return errors.NewBusinessError(errors.ValidationInvalidName, "name cannot be only whitespace")
}
return nil
}
func ValidateRequestTxt(txt string) error {
if len(txt) > MaxRequestTxtLen {
return errors.NewBusinessError(errors.ValidationRequestTooLong, "request text exceeds 50000 characters limit")
}
return nil
}
func ValidateFileSize(size int) error {
if size > MaxFileSizeBytes {
return errors.NewBusinessError(errors.ValidationFileTooLarge, "file size exceeds 10MB limit")
}
return nil
}
func ValidateRegistration(email, password, name, phone string) error {
if err := ValidateEmail(email); err != nil {
return err
}
if err := ValidatePassword(password); err != nil {
return err
}
if err := ValidateName(name); err != nil {
return err
}
if err := ValidatePhone(phone); err != nil {
return err
}
return nil
}