userutil.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. // Copyright 2022 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE.gogs file.
  4. package userutil
  5. import (
  6. "bytes"
  7. "crypto/sha256"
  8. "crypto/subtle"
  9. "fmt"
  10. "github.com/nfnt/resize"
  11. "github.com/pkg/errors"
  12. "golang.org/x/crypto/pbkdf2"
  13. "image"
  14. "image/png"
  15. "os"
  16. "path/filepath"
  17. "strconv"
  18. "gogs.io/gogs/internal/avatar"
  19. "gogs.io/gogs/internal/conf"
  20. "gogs.io/gogs/internal/strutil"
  21. )
  22. // DashboardURLPath returns the URL path to the user or organization dashboard.
  23. func DashboardURLPath(name string, isOrganization bool) string {
  24. if isOrganization {
  25. return conf.Server.Subpath + "/org/" + name + "/dashboard/"
  26. }
  27. return conf.Server.Subpath + "/"
  28. }
  29. // CustomAvatarPath returns the absolute path of the user custom avatar file.
  30. func CustomAvatarPath(userID int64) string {
  31. return filepath.Join(conf.Picture.AvatarUploadPath, strconv.FormatInt(userID, 10))
  32. }
  33. // GenerateRandomAvatar generates a random avatar and stores to local file
  34. // system using given user information.
  35. func GenerateRandomAvatar(userID int64, name, email string) error {
  36. seed := email
  37. if seed == "" {
  38. seed = name
  39. }
  40. img, err := avatar.RandomImage([]byte(seed))
  41. if err != nil {
  42. return errors.Wrap(err, "generate random image")
  43. }
  44. avatarPath := CustomAvatarPath(userID)
  45. err = os.MkdirAll(filepath.Dir(avatarPath), os.ModePerm)
  46. if err != nil {
  47. return errors.Wrap(err, "create avatar directory")
  48. }
  49. f, err := os.Create(avatarPath)
  50. if err != nil {
  51. return errors.Wrap(err, "create avatar file")
  52. }
  53. defer func() { _ = f.Close() }()
  54. if err = png.Encode(f, img); err != nil {
  55. return errors.Wrap(err, "encode avatar image to file")
  56. }
  57. return nil
  58. }
  59. // SaveAvatar saves the given avatar for the user.
  60. func SaveAvatar(userID int64, data []byte) error {
  61. img, _, err := image.Decode(bytes.NewReader(data))
  62. if err != nil {
  63. return errors.Wrap(err, "decode image")
  64. }
  65. avatarPath := CustomAvatarPath(userID)
  66. err = os.MkdirAll(filepath.Dir(avatarPath), os.ModePerm)
  67. if err != nil {
  68. return errors.Wrap(err, "create avatar directory")
  69. }
  70. f, err := os.Create(avatarPath)
  71. if err != nil {
  72. return errors.Wrap(err, "create avatar file")
  73. }
  74. defer func() { _ = f.Close() }()
  75. m := resize.Resize(avatar.DefaultSize, avatar.DefaultSize, img, resize.NearestNeighbor)
  76. if err = png.Encode(f, m); err != nil {
  77. return errors.Wrap(err, "encode avatar image to file")
  78. }
  79. return nil
  80. }
  81. // EncodePassword encodes password using PBKDF2 SHA256 with given salt.
  82. func EncodePassword(password, salt string) string {
  83. newPasswd := pbkdf2.Key([]byte(password), []byte(salt), 10000, 50, sha256.New)
  84. return fmt.Sprintf("%x", newPasswd)
  85. }
  86. // ValidatePassword returns true if the given password matches the encoded
  87. // version with given salt.
  88. func ValidatePassword(encoded, salt, password string) bool {
  89. got := EncodePassword(password, salt)
  90. return subtle.ConstantTimeCompare([]byte(encoded), []byte(got)) == 1
  91. }
  92. // MailResendCacheKey returns the key used for caching mail resend.
  93. func MailResendCacheKey(userID int64) string {
  94. return fmt.Sprintf("mailResend::%d", userID)
  95. }
  96. // TwoFactorCacheKey returns the key used for caching two factor passcode.
  97. func TwoFactorCacheKey(userID int64, passcode string) string {
  98. return fmt.Sprintf("twoFactor::%d::%s", userID, passcode)
  99. }
  100. // RandomSalt returns randomly generated 10-character string that can be used as
  101. // the user salt.
  102. func RandomSalt() (string, error) {
  103. return strutil.RandomChars(10)
  104. }