diff --git a/pkg/integrations/register_test.go b/pkg/integrations/register_test.go index 0dec4df0024..41001dab906 100644 --- a/pkg/integrations/register_test.go +++ b/pkg/integrations/register_test.go @@ -29,7 +29,7 @@ func TestRegister(t *testing.T) { t.Run("normal register", func(t *testing.T) { rec, err := newTestRequest(t, http.MethodPost, apiv1.RegisterUser, `{ "username": "newUser", - "password": "1234", + "password": "12345678", "email": "email@example.com" }`, nil, nil) assert.NoError(t, err) @@ -43,7 +43,7 @@ func TestRegister(t *testing.T) { t.Run("Empty username", func(t *testing.T) { _, err := newTestRequest(t, http.MethodPost, apiv1.RegisterUser, `{ "username": "", - "password": "1234", + "password": "12345678", "email": "email@example.com" }`, nil, nil) assert.Error(t, err) @@ -61,7 +61,7 @@ func TestRegister(t *testing.T) { t.Run("Empty email", func(t *testing.T) { _, err := newTestRequest(t, http.MethodPost, apiv1.RegisterUser, `{ "username": "newUser", - "password": "1234", + "password": "12345678", "email": "" }`, nil, nil) assert.Error(t, err) @@ -70,7 +70,7 @@ func TestRegister(t *testing.T) { t.Run("Already existing username", func(t *testing.T) { _, err := newTestRequest(t, http.MethodPost, apiv1.RegisterUser, `{ "username": "user1", - "password": "1234", + "password": "12345678", "email": "email@example.com" }`, nil, nil) assert.Error(t, err) @@ -79,7 +79,7 @@ func TestRegister(t *testing.T) { t.Run("Already existing email", func(t *testing.T) { _, err := newTestRequest(t, http.MethodPost, apiv1.RegisterUser, `{ "username": "newUser", - "password": "1234", + "password": "12345678", "email": "user1@example.com" }`, nil, nil) assert.Error(t, err) diff --git a/pkg/routes/api/v1/user_register.go b/pkg/routes/api/v1/user_register.go index b8d408e3a5d..33a3d927c86 100644 --- a/pkg/routes/api/v1/user_register.go +++ b/pkg/routes/api/v1/user_register.go @@ -17,6 +17,7 @@ package v1 import ( + "errors" "net/http" "code.vikunja.io/api/pkg/db" @@ -44,11 +45,19 @@ func RegisterUser(c echo.Context) error { return echo.ErrNotFound } // Check for Request Content - var datUser *user.APIUserPassword - if err := c.Bind(&datUser); err != nil { + var userIn *user.APIUserPassword + if err := c.Bind(&userIn); err != nil { return c.JSON(http.StatusBadRequest, models.Message{Message: "No or invalid user model provided."}) } - if datUser == nil { + if err := c.Validate(userIn); err != nil { + e := models.ValidationHTTPError{} + if is := errors.As(err, &e); is { + return c.JSON(e.HTTPCode, e) + } + + return handler.HandleHTTPError(err, c) + } + if userIn == nil { return c.JSON(http.StatusBadRequest, models.Message{Message: "No or invalid user model provided."}) } @@ -56,7 +65,7 @@ func RegisterUser(c echo.Context) error { defer s.Close() // Insert the user - newUser, err := user.CreateUser(s, datUser.APIFormat()) + newUser, err := user.CreateUser(s, userIn.APIFormat()) if err != nil { _ = s.Rollback() return handler.HandleHTTPError(err, c) diff --git a/pkg/routes/validation.go b/pkg/routes/validation.go index 09e2a313d1c..5f01eac39b3 100644 --- a/pkg/routes/validation.go +++ b/pkg/routes/validation.go @@ -17,6 +17,8 @@ package routes import ( + "net/http" + "code.vikunja.io/api/pkg/models" "code.vikunja.io/web" @@ -41,15 +43,14 @@ func (cv *CustomValidator) Validate(i interface{}) error { errs = append(errs, field+": "+e) } - httperr := models.ValidationHTTPError{ + return models.ValidationHTTPError{ HTTPError: web.HTTPError{ - Code: models.ErrCodeInvalidData, - Message: "Invalid Data", + HTTPCode: http.StatusPreconditionFailed, + Code: models.ErrCodeInvalidData, + Message: "Invalid Data", }, InvalidFields: errs, } - - return httperr } return nil } diff --git a/pkg/user/user.go b/pkg/user/user.go index 6191e8755f7..69618b909da 100644 --- a/pkg/user/user.go +++ b/pkg/user/user.go @@ -183,8 +183,8 @@ func GetFromAuth(a web.Auth) (*User, error) { type APIUserPassword struct { // The unique, numeric id of this user. ID int64 `json:"id"` - // The username of the username. Is always unique. - Username string `json:"username" valid:"length(3|250)" minLength:"3" maxLength:"250"` + // The user's username. Cannot contain anything that looks like an url or whitespaces. + Username string `json:"username" valid:"length(3|250),username" minLength:"3" maxLength:"250"` // The user's password in clear text. Only used when registering the user. Password string `json:"password" valid:"length(8|250)" minLength:"8" maxLength:"250"` // The user's email address diff --git a/pkg/user/username_valid.go b/pkg/user/username_valid.go new file mode 100644 index 00000000000..0ac77ea1988 --- /dev/null +++ b/pkg/user/username_valid.go @@ -0,0 +1,36 @@ +// Vikunja is a to-do list application to facilitate your life. +// Copyright 2018-present Vikunja and contributors. All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public Licensee 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 Affero General Public Licensee for more details. +// +// You should have received a copy of the GNU Affero General Public Licensee +// along with this program. If not, see . + +package user + +import "github.com/asaskevich/govalidator" + +func init() { + govalidator.TagMap["username"] = func(i string) bool { + // To avoid making this overly complicated, we only two things: + // 1. No Spaces + // 2. Should not look like an url + if govalidator.IsURL(i) { + return false + } + + if govalidator.HasWhitespace(i) { + return false + } + + return true + } +}