diff options
Diffstat (limited to 'models/user.go')
-rw-r--r-- | models/user.go | 48 |
1 files changed, 41 insertions, 7 deletions
diff --git a/models/user.go b/models/user.go index aa392b1ea9..fc0dfee187 100644 --- a/models/user.go +++ b/models/user.go @@ -33,7 +33,10 @@ import ( "github.com/Unknwon/com" "github.com/go-xorm/xorm" + "golang.org/x/crypto/argon2" + "golang.org/x/crypto/bcrypt" "golang.org/x/crypto/pbkdf2" + "golang.org/x/crypto/scrypt" "golang.org/x/crypto/ssh" "xorm.io/builder" "xorm.io/core" @@ -50,6 +53,13 @@ const ( UserTypeOrganization ) +const ( + algoBcrypt = "bcrypt" + algoScrypt = "scrypt" + algoArgon2 = "argon2" + algoPbkdf2 = "pbkdf2" +) + const syncExternalUsers = "sync_external_users" var ( @@ -82,6 +92,7 @@ type User struct { Email string `xorm:"NOT NULL"` KeepEmailPrivate bool Passwd string `xorm:"NOT NULL"` + PasswdHashAlgo string `xorm:"NOT NULL DEFAULT 'pbkdf2'"` // MustChangePassword is an attribute that determines if a user // is to change his/her password after registration. @@ -430,25 +441,48 @@ func (u *User) NewGitSig() *git.Signature { } } -func hashPassword(passwd, salt string) string { - tempPasswd := pbkdf2.Key([]byte(passwd), []byte(salt), 10000, 50, sha256.New) +func hashPassword(passwd, salt, algo string) string { + var tempPasswd []byte + + switch algo { + case algoBcrypt: + tempPasswd, _ = bcrypt.GenerateFromPassword([]byte(passwd), bcrypt.DefaultCost) + return string(tempPasswd) + case algoScrypt: + tempPasswd, _ = scrypt.Key([]byte(passwd), []byte(salt), 65536, 16, 2, 50) + case algoArgon2: + tempPasswd = argon2.IDKey([]byte(passwd), []byte(salt), 2, 65536, 8, 50) + case algoPbkdf2: + fallthrough + default: + tempPasswd = pbkdf2.Key([]byte(passwd), []byte(salt), 10000, 50, sha256.New) + } + return fmt.Sprintf("%x", tempPasswd) } -// HashPassword hashes a password using PBKDF. +// HashPassword hashes a password using the algorithm defined in the config value of PASSWORD_HASH_ALGO. func (u *User) HashPassword(passwd string) { - u.Passwd = hashPassword(passwd, u.Salt) + u.PasswdHashAlgo = setting.PasswordHashAlgo + u.Passwd = hashPassword(passwd, u.Salt, setting.PasswordHashAlgo) } // ValidatePassword checks if given password matches the one belongs to the user. func (u *User) ValidatePassword(passwd string) bool { - tempHash := hashPassword(passwd, u.Salt) - return subtle.ConstantTimeCompare([]byte(u.Passwd), []byte(tempHash)) == 1 + tempHash := hashPassword(passwd, u.Salt, u.PasswdHashAlgo) + + if u.PasswdHashAlgo != algoBcrypt && subtle.ConstantTimeCompare([]byte(u.Passwd), []byte(tempHash)) == 1 { + return true + } + if u.PasswdHashAlgo == algoBcrypt && bcrypt.CompareHashAndPassword([]byte(u.Passwd), []byte(passwd)) == nil { + return true + } + return false } // IsPasswordSet checks if the password is set or left empty func (u *User) IsPasswordSet() bool { - return !u.ValidatePassword("") + return len(u.Passwd) > 0 } // UploadAvatar saves custom avatar for user. |