package main import ( "encoding/json" "net/http" "unicode" "github.com/go-playground/validator/v10" ) var Validate *validator.Validate func init() { Validate = validator.New(validator.WithRequiredStructEnabled()) Validate.RegisterValidation("password", validatePassword) } func writeJSON(w http.ResponseWriter, status int, data any) error { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) return json.NewEncoder(w).Encode(data) } func readJSON(w http.ResponseWriter, r *http.Request, data any) error { maxBytes := 1_048_578 // 1MB r.Body = http.MaxBytesReader(w, r.Body, int64(maxBytes)) decoder := json.NewDecoder(r.Body) decoder.DisallowUnknownFields() return decoder.Decode(data) } func errorJSON(w http.ResponseWriter, status int, err string) error { type envelope struct { Error string `json:"error"` } return writeJSON(w, status, &envelope{Error: err}) } func (api *api) jsonResponse(w http.ResponseWriter, status int, data any) error { type envelope struct { Data any `json:"data"` } return writeJSON(w, status, &envelope{Data: data}) } func validatePassword(fl validator.FieldLevel) bool { password := fl.Field().String() var ( hasMinLen = len(password) >= 8 hasMaxLen = len(password) <= 72 hasUpper = false hasLower = false hasNumber = false hasSymbol = 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): hasSymbol = true } } return hasMinLen && hasMaxLen && hasUpper && hasLower && hasNumber && hasSymbol }