summaryrefslogtreecommitdiff
path: root/user/validate.go
diff options
context:
space:
mode:
Diffstat (limited to 'user/validate.go')
-rw-r--r--user/validate.go153
1 files changed, 153 insertions, 0 deletions
diff --git a/user/validate.go b/user/validate.go
new file mode 100644
index 0000000..b51757f
--- /dev/null
+++ b/user/validate.go
@@ -0,0 +1,153 @@
+/* OpenBills-server - Server for libre billing software OpenBills-web
+ * Copyright (C) 2022 Vidhu Kant Sharma <vidhukant@vidhukant.xyz>
+
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+
+package user
+
+import (
+ "context"
+ "strings"
+ "net/mail"
+ "net/http"
+ "log"
+ "github.com/gin-gonic/gin"
+ "go.mongodb.org/mongo-driver/mongo"
+ "go.mongodb.org/mongo-driver/bson"
+ "errors"
+)
+
+var (
+ errUsernameTaken = errors.New("username is taken")
+ errUsernameTooShort = errors.New("username is too short")
+ errUsernameInvalid = errors.New("invalid username")
+ errEmailTaken = errors.New("email is taken")
+ errEmailInvalid = errors.New("email is invalid")
+ errPasswordTooShort = errors.New("password is too short")
+)
+
+func isUsernameTaken(username string) error {
+ var x User
+ err := db.FindOne(context.TODO(), bson.M{"UserName": username}).Decode(&x)
+ if err != nil {
+ if err == mongo.ErrNoDocuments {
+ return nil
+ } else {
+ return err
+ }
+ } else {
+ return errUsernameTaken
+ }
+ return nil
+}
+
+func isEmailTaken(email string) error {
+ var x User
+ err := db.FindOne(context.TODO(), bson.M{"Email": email}).Decode(&x)
+ if err != nil {
+ if err == mongo.ErrNoDocuments {
+ return nil
+ } else {
+ return err
+ }
+ } else {
+ return errEmailTaken
+ }
+ return nil
+}
+
+func validateUsername(username string) error {
+ username = strings.Trim(username, " ")
+
+ if len(username) < 2 {
+ return errUsernameTooShort
+ }
+
+ if strings.Contains(username, " ") {
+ return errUsernameInvalid
+ }
+
+ return isUsernameTaken(username)
+}
+
+func validateEmail(email string) error {
+ email = strings.Trim(email, " ")
+
+ // verify if string is valid email
+ _, err := mail.ParseAddress(email)
+ if err != nil {
+ return errEmailInvalid
+ }
+
+ return isEmailTaken(email)
+}
+
+func validatePassword(password string) error {
+ // TODO: load password length from config
+ if len(password) < 12 {
+ return errPasswordTooShort
+ }
+
+ return nil
+}
+
+func validateMiddleware() gin.HandlerFunc {
+ return func(ctx *gin.Context) {
+ var u User
+ ctx.BindJSON(&u)
+
+ // validate username
+ isUsernameValid := validateUsername(u.UserName)
+ switch isUsernameValid {
+ case nil:
+ break;
+ case errUsernameTooShort, errUsernameInvalid:
+ ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": isUsernameValid.Error()})
+ case errUsernameTaken:
+ ctx.AbortWithStatusJSON(http.StatusConflict, gin.H{"error": isUsernameValid.Error()})
+ default:
+ log.Printf("Error while creating new user '%s': %s", u.UserName, isUsernameValid.Error())
+ ctx.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "internal server error (cannot create user)"})
+ }
+
+ // validate email
+ isEmailValid := validateEmail(u.Email)
+ switch isEmailValid {
+ case nil:
+ break;
+ case errEmailInvalid:
+ ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": isEmailValid.Error()})
+ case errEmailTaken:
+ ctx.AbortWithStatusJSON(http.StatusConflict, gin.H{"error": isEmailValid.Error()})
+ default:
+ log.Printf("Error while creating new user '%s': %s", u.UserName, isEmailValid.Error())
+ ctx.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "internal server error (cannot create user)"})
+ }
+
+ // validate password
+ isPasswordValid := validatePassword(u.Password)
+ switch isPasswordValid {
+ case nil:
+ break;
+ case errPasswordTooShort:
+ ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": isPasswordValid.Error()})
+ default:
+ ctx.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "internal server error (cannot create user)"})
+ log.Printf("Error while creating new user '%s': %s", u.UserName, isPasswordValid.Error())
+ }
+
+ ctx.Set("user", u)
+ }
+}