/* openbills - Server for web based Libre Billing Software * Copyright (C) 2023-2024 Vidhu Kant Sharma * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package user import ( "strings" e "errors" "github.com/spf13/viper" "vidhukant.com/openbills/errors" "vidhukant.com/openbills/util" ) func validatePassword(pass string) error { // check if password is too short if len(pass) < viper.GetInt("security.min_password_length") { return errors.ErrPasswordTooShort } // check if password is too long if len(pass) > viper.GetInt("security.max_password_length") { return errors.ErrPasswordTooLong } return nil } func validateUsername(username string) error { // check if username is too short if len(username) < viper.GetInt("username.min_username_length") { return errors.ErrUsernameTooShort } // check if username is too long if len(username) > viper.GetInt("username.max_username_length") { return errors.ErrUsernameTooLong } for _, char := range username { if !strings.Contains(username, string(char)) { return errors.ErrInvalidUsername } } return nil } // NOTE: very inefficient and really really really dumb but it works // TODO: find a better (or even a remotely good) way func validateUserField(field, value string) error { if value != "" { var count int64 err := db.Model(&User{}). Where(field + " = ?", value). Count(&count). Error if err != nil { return err } if count > 0 { switch(field) { case "username": return errors.ErrNonUniqueUsername case "phone": return errors.ErrNonUniquePhone case "email": return errors.ErrNonUniqueEmail case "website": return errors.ErrNonUniqueWebsite case "gstin": return errors.ErrNonUniqueGSTIN default: return e.New(field + " is not unique") } } } return nil } func (u *User) validate() error { u.Username = strings.TrimSpace(u.Username) u.Email = strings.TrimSpace(u.Email) u.Phone = strings.TrimSpace(u.Phone) u.Website = strings.TrimSpace(u.Website) u.Gstin = strings.TrimSpace(u.Gstin) u.IsVerified = false // TODO: validate username length and stuff // don't validate if GSTIN is empty if u.Gstin != "" && !util.ValidateGstin(u.Gstin) { return errors.ErrInvalidGSTIN } // don't validate if phone is empty if u.Phone != "" && !util.ValidatePhone(u.Phone) { return errors.ErrInvalidPhone } // don't validate if website is empty if u.Website != "" && !util.ValidateWebsite(u.Website) { return errors.ErrInvalidWebsite } // don't accept empty email if u.Email == "" { return errors.ErrEmptyEmail } else { // validate email if !util.ValidateEmail(u.Email) { return errors.ErrInvalidEmail } } // don't accept empty username if u.Username == "" { return errors.ErrEmptyUsername } else { // validate username err := validateUsername(u.Username) if err != nil { return err } } // validate password err := validatePassword(u.Password) if err != nil { return err } for _, i := range [][]string{{"username", u.Username}, {"email", u.Email}, {"website", u.Website}, {"gstin", u.Gstin}, {"phone", u.Phone}} { err := validateUserField(i[0], i[1]) if err != nil { return err } } return nil }