You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

v166.go 2.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. // Copyright 2021 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package v1_14 //nolint
  4. import (
  5. "encoding/hex"
  6. "github.com/minio/sha256-simd"
  7. "golang.org/x/crypto/argon2"
  8. "golang.org/x/crypto/bcrypt"
  9. "golang.org/x/crypto/pbkdf2"
  10. "golang.org/x/crypto/scrypt"
  11. "xorm.io/builder"
  12. "xorm.io/xorm"
  13. )
  14. func RecalculateUserEmptyPWD(x *xorm.Engine) (err error) {
  15. const (
  16. algoBcrypt = "bcrypt"
  17. algoScrypt = "scrypt"
  18. algoArgon2 = "argon2"
  19. algoPbkdf2 = "pbkdf2"
  20. )
  21. type User struct {
  22. ID int64 `xorm:"pk autoincr"`
  23. Passwd string `xorm:"NOT NULL"`
  24. PasswdHashAlgo string `xorm:"NOT NULL DEFAULT 'argon2'"`
  25. MustChangePassword bool `xorm:"NOT NULL DEFAULT false"`
  26. LoginType int
  27. LoginName string
  28. Type int
  29. Salt string `xorm:"VARCHAR(10)"`
  30. }
  31. // hashPassword hash password based on algo and salt
  32. // state 461406070c
  33. hashPassword := func(passwd, salt, algo string) string {
  34. var tempPasswd []byte
  35. switch algo {
  36. case algoBcrypt:
  37. tempPasswd, _ = bcrypt.GenerateFromPassword([]byte(passwd), bcrypt.DefaultCost)
  38. return string(tempPasswd)
  39. case algoScrypt:
  40. tempPasswd, _ = scrypt.Key([]byte(passwd), []byte(salt), 65536, 16, 2, 50)
  41. case algoArgon2:
  42. tempPasswd = argon2.IDKey([]byte(passwd), []byte(salt), 2, 65536, 8, 50)
  43. case algoPbkdf2:
  44. fallthrough
  45. default:
  46. tempPasswd = pbkdf2.Key([]byte(passwd), []byte(salt), 10000, 50, sha256.New)
  47. }
  48. return hex.EncodeToString(tempPasswd)
  49. }
  50. // ValidatePassword checks if given password matches the one belongs to the user.
  51. // state 461406070c, changed since it's not necessary to be time constant
  52. ValidatePassword := func(u *User, passwd string) bool {
  53. tempHash := hashPassword(passwd, u.Salt, u.PasswdHashAlgo)
  54. if u.PasswdHashAlgo != algoBcrypt && u.Passwd == tempHash {
  55. return true
  56. }
  57. if u.PasswdHashAlgo == algoBcrypt && bcrypt.CompareHashAndPassword([]byte(u.Passwd), []byte(passwd)) == nil {
  58. return true
  59. }
  60. return false
  61. }
  62. sess := x.NewSession()
  63. defer sess.Close()
  64. const batchSize = 100
  65. for start := 0; ; start += batchSize {
  66. users := make([]*User, 0, batchSize)
  67. if err = sess.Limit(batchSize, start).Where(builder.Neq{"passwd": ""}, 0).Find(&users); err != nil {
  68. return err
  69. }
  70. if len(users) == 0 {
  71. break
  72. }
  73. if err = sess.Begin(); err != nil {
  74. return err
  75. }
  76. for _, user := range users {
  77. if ValidatePassword(user, "") {
  78. user.Passwd = ""
  79. user.Salt = ""
  80. user.PasswdHashAlgo = ""
  81. if _, err = sess.ID(user.ID).Cols("passwd", "salt", "passwd_hash_algo").Update(user); err != nil {
  82. return err
  83. }
  84. }
  85. }
  86. if err = sess.Commit(); err != nil {
  87. return err
  88. }
  89. }
  90. // delete salt and algo where password is empty
  91. _, err = sess.Where(builder.Eq{"passwd": ""}.And(builder.Neq{"salt": ""}.Or(builder.Neq{"passwd_hash_algo": ""}))).
  92. Cols("salt", "passwd_hash_algo").Update(&User{})
  93. return err
  94. }