From 05a5c59a7e3b12f5bf42beb003a065e63a093db9 Mon Sep 17 00:00:00 2001 From: Steven Date: Sat, 20 Aug 2022 21:03:15 +0800 Subject: [PATCH] chore: update user create validator --- api/user.go | 20 ++++++++++++++++++++ common/error.go | 5 ----- common/util.go | 9 +++++++++ common/util_test.go | 31 +++++++++++++++++++++++++++++++ server/auth.go | 23 ++++++++++------------- server/user.go | 18 ++++++++++++++++++ 6 files changed, 88 insertions(+), 18 deletions(-) create mode 100644 common/util_test.go diff --git a/api/user.go b/api/user.go index 5d1634d6..606fcc1b 100644 --- a/api/user.go +++ b/api/user.go @@ -1,5 +1,11 @@ package api +import ( + "fmt" + + "github.com/usememos/memos/common" +) + // Role is the type of a role. type Role string @@ -47,6 +53,20 @@ type UserCreate struct { OpenID string } +func (create UserCreate) Validate() error { + if !common.ValidateEmail(create.Email) { + return fmt.Errorf("invalid email format") + } + if len(create.Email) < 6 { + return fmt.Errorf("email is too short, minimum length is 6") + } + if len(create.Password) < 6 { + return fmt.Errorf("password is too short, minimum length is 6") + } + + return nil +} + type UserPatch struct { ID int diff --git a/common/error.go b/common/error.go index ef792ed4..b4d24e18 100644 --- a/common/error.go +++ b/common/error.go @@ -17,11 +17,6 @@ const ( NotFound Code = 4 Conflict Code = 5 NotImplemented Code = 6 - - // 101 ~ 199 db error - DbConnectionFailure Code = 101 - DbStatementSyntaxError Code = 102 - DbExecutionError Code = 103 ) // Error represents an application-specific error. Application errors can be diff --git a/common/util.go b/common/util.go index 411f3fbc..1c8a0246 100644 --- a/common/util.go +++ b/common/util.go @@ -1,6 +1,7 @@ package common import ( + "net/mail" "strings" "github.com/google/uuid" @@ -16,6 +17,14 @@ func HasPrefixes(src string, prefixes ...string) bool { return false } +// ValidateEmail validates the email. +func ValidateEmail(email string) bool { + if _, err := mail.ParseAddress(email); err != nil { + return false + } + return true +} + func GenUUID() string { return uuid.New().String() } diff --git a/common/util_test.go b/common/util_test.go new file mode 100644 index 00000000..9cd7af82 --- /dev/null +++ b/common/util_test.go @@ -0,0 +1,31 @@ +package common + +import ( + "testing" +) + +func TestValidateEmail(t *testing.T) { + tests := []struct { + email string + want bool + }{ + { + email: "t@gmail.com", + want: true, + }, + { + email: "@qq.com", + want: false, + }, + { + email: "1@gmail", + want: true, + }, + } + for _, test := range tests { + result := ValidateEmail(test.email) + if result != test.want { + t.Errorf("Validate Email %s: got result %v, want %v.", test.email, result, test.want) + } + } +} diff --git a/server/auth.go b/server/auth.go index 967be228..7517551e 100644 --- a/server/auth.go +++ b/server/auth.go @@ -80,13 +80,15 @@ func (s *Server) registerAuthRoutes(g *echo.Group) { return echo.NewHTTPError(http.StatusBadRequest, "Malformatted signup request").SetInternal(err) } - // Validate signup form. - // We can do stricter checks later. - if len(signup.Email) < 6 { - return echo.NewHTTPError(http.StatusBadRequest, "Email is too short, minimum length is 6.") + userCreate := &api.UserCreate{ + Email: signup.Email, + Role: api.Role(signup.Role), + Name: signup.Name, + Password: signup.Password, + OpenID: common.GenUUID(), } - if len(signup.Password) < 6 { - return echo.NewHTTPError(http.StatusBadRequest, "Password is too short, minimum length is 6.") + if err := userCreate.Validate(); err != nil { + return echo.NewHTTPError(http.StatusBadRequest, "Invalid user create format.").SetInternal(err) } passwordHash, err := bcrypt.GenerateFromPassword([]byte(signup.Password), bcrypt.DefaultCost) @@ -94,13 +96,8 @@ func (s *Server) registerAuthRoutes(g *echo.Group) { return echo.NewHTTPError(http.StatusInternalServerError, "Failed to generate password hash").SetInternal(err) } - userCreate := &api.UserCreate{ - Email: signup.Email, - Role: api.Role(signup.Role), - Name: signup.Name, - PasswordHash: string(passwordHash), - OpenID: common.GenUUID(), - } + userCreate.PasswordHash = string(passwordHash) + user, err := s.Store.CreateUser(ctx, userCreate) if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create user").SetInternal(err) diff --git a/server/user.go b/server/user.go index 8210e91e..57102ce9 100644 --- a/server/user.go +++ b/server/user.go @@ -16,11 +16,29 @@ import ( func (s *Server) registerUserRoutes(g *echo.Group) { g.POST("/user", func(c echo.Context) error { ctx := c.Request().Context() + userID, ok := c.Get(getUserIDContextKey()).(int) + if !ok { + return echo.NewHTTPError(http.StatusUnauthorized, "Missing auth session") + } + currentUser, err := s.Store.FindUser(ctx, &api.UserFind{ + ID: &userID, + }) + if err != nil { + return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find user by id").SetInternal(err) + } + if currentUser.Role != api.Host { + return echo.NewHTTPError(http.StatusUnauthorized, "Only Host user can create member.") + } + userCreate := &api.UserCreate{} if err := json.NewDecoder(c.Request().Body).Decode(userCreate); err != nil { return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post user request").SetInternal(err) } + if err := userCreate.Validate(); err != nil { + return echo.NewHTTPError(http.StatusBadRequest, "Invalid user create format.").SetInternal(err) + } + passwordHash, err := bcrypt.GenerateFromPassword([]byte(userCreate.Password), bcrypt.DefaultCost) if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, "Failed to generate password hash").SetInternal(err)