fix(auth): restrict max password length to 72 bytes
Some checks failed
continuous-integration/drone/push Build is failing

Bcrypt allows a maximum of 72 bytes. This is part of the algorithm and not something we could change in Vikunja. The solution here was to restrict the password during registration to a max length of 72 bytes. In the future, this should be changed to hash passwords with sha512 or similar before hashing them with bcrypt. Because they should also be salted in that case and the added complexity during the migration phase, this was not implemented yet.
The change in this commit only improves the error handling to return an input error instead of a server error when the user enters a password > 72 bytes.

Resolves https://vikunja.sentry.io/share/issue/e8e0b64612d84504942feee002ac498a/
This commit is contained in:
kolaente 2024-09-10 18:23:06 +02:00
parent eb95caf757
commit 44a43b9f86
Signed by: konrad
GPG Key ID: F40E70337AB24C9B
4 changed files with 17 additions and 7 deletions

@ -7,7 +7,7 @@ export function validatePassword(password: string, validateMinLength: boolean =
return 'user.auth.passwordNotMin'
}
if (validateMinLength && password.length > 250) {
if (validateMinLength && password.length > 72) {
return 'user.auth.passwordNotMax'
}

@ -61,7 +61,7 @@
"usernameMustNotLookLikeUrl": "The username must not look like a URL.",
"passwordRequired": "Please provide a password.",
"passwordNotMin": "Password must have at least 8 characters.",
"passwordNotMax": "Password must have at most 250 characters.",
"passwordNotMax": "Password must have at most 72 characters.",
"showPassword": "Show the password",
"hidePassword": "Hide the password",
"noAccountYet": "Don't have an account yet?",

@ -197,8 +197,8 @@ type APIUserPassword struct {
ID int64 `json:"id"`
// 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 password in clear text. Only used when registering the user. The maximum limi is 72 bytes, which may be less than 72 characters. This is due to the limit in the bcrypt hashing algorithm used to store passwords in Vikunja.
Password string `json:"password" valid:"bcrypt_password" minLength:"8" maxLength:"72"`
// The user's email address
Email string `json:"email" valid:"email,length(0|250)" maxLength:"250"`
}
@ -213,7 +213,7 @@ func (apiUser *APIUserPassword) APIFormat() *User {
}
}
// GetUserByID gets informations about a user by its ID
// GetUserByID returns user by its ID
func GetUserByID(s *xorm.Session, id int64) (user *User, err error) {
// Apparently xorm does otherwise look for all users but return only one, which leads to returning one even if the ID is 0
if id < 1 {
@ -223,7 +223,7 @@ func GetUserByID(s *xorm.Session, id int64) (user *User, err error) {
return getUser(s, &User{ID: id}, false)
}
// GetUserByUsername gets a user from its user name. This is an extra function to be able to add an extra error check.
// GetUserByUsername gets a user from its username. This is an extra function to be able to add an extra error check.
func GetUserByUsername(s *xorm.Session, username string) (user *User, err error) {
if username == "" {
return &User{}, ErrUserDoesNotExist{}

@ -16,7 +16,9 @@
package user
import "github.com/asaskevich/govalidator"
import (
"github.com/asaskevich/govalidator"
)
func init() {
govalidator.TagMap["username"] = func(i string) bool {
@ -33,4 +35,12 @@ func init() {
return true
}
govalidator.TagMap["bcrypt_password"] = func(str string) bool {
if len(str) < 8 {
return false
}
return len([]byte(str)) < 72
}
}