userutil.go 3.9 KB

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