userutil.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  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/tool"
  23. )
  24. // DashboardURLPath returns the URL path to the user or organization dashboard.
  25. func DashboardURLPath(name string, isOrganization bool) string {
  26. if isOrganization {
  27. return conf.Server.Subpath + "/org/" + name + "/dashboard/"
  28. }
  29. return conf.Server.Subpath + "/"
  30. }
  31. // GenerateActivateCode generates an activate code based on user information and
  32. // the given email.
  33. func GenerateActivateCode(userID int64, email, name, password, rands string) string {
  34. code := tool.CreateTimeLimitCode(
  35. fmt.Sprintf("%d%s%s%s%s", userID, email, strings.ToLower(name), password, rands),
  36. conf.Auth.ActivateCodeLives,
  37. nil,
  38. )
  39. // Add tailing hex username
  40. code += hex.EncodeToString([]byte(strings.ToLower(name)))
  41. return code
  42. }
  43. // CustomAvatarPath returns the absolute path of the user custom avatar file.
  44. func CustomAvatarPath(userID int64) string {
  45. return filepath.Join(conf.Picture.AvatarUploadPath, strconv.FormatInt(userID, 10))
  46. }
  47. // GenerateRandomAvatar generates a random avatar and stores to local file
  48. // system using given user information.
  49. func GenerateRandomAvatar(userID int64, name, email string) error {
  50. seed := email
  51. if seed == "" {
  52. seed = name
  53. }
  54. img, err := avatar.RandomImage([]byte(seed))
  55. if err != nil {
  56. return errors.Wrap(err, "generate random image")
  57. }
  58. avatarPath := CustomAvatarPath(userID)
  59. err = os.MkdirAll(filepath.Dir(avatarPath), os.ModePerm)
  60. if err != nil {
  61. return errors.Wrap(err, "create avatar directory")
  62. }
  63. f, err := os.Create(avatarPath)
  64. if err != nil {
  65. return errors.Wrap(err, "create avatar file")
  66. }
  67. defer func() { _ = f.Close() }()
  68. if err = png.Encode(f, img); err != nil {
  69. return errors.Wrap(err, "encode avatar image to file")
  70. }
  71. return nil
  72. }
  73. // SaveAvatar saves the given avatar for the user.
  74. func SaveAvatar(userID int64, data []byte) error {
  75. img, _, err := image.Decode(bytes.NewReader(data))
  76. if err != nil {
  77. return errors.Wrap(err, "decode image")
  78. }
  79. avatarPath := CustomAvatarPath(userID)
  80. err = os.MkdirAll(filepath.Dir(avatarPath), os.ModePerm)
  81. if err != nil {
  82. return errors.Wrap(err, "create avatar directory")
  83. }
  84. f, err := os.Create(avatarPath)
  85. if err != nil {
  86. return errors.Wrap(err, "create avatar file")
  87. }
  88. defer func() { _ = f.Close() }()
  89. m := resize.Resize(avatar.DefaultSize, avatar.DefaultSize, img, resize.NearestNeighbor)
  90. if err = png.Encode(f, m); err != nil {
  91. return errors.Wrap(err, "encode avatar image to file")
  92. }
  93. return nil
  94. }
  95. // EncodePassword encodes password using PBKDF2 SHA256 with given salt.
  96. func EncodePassword(password, salt string) string {
  97. newPasswd := pbkdf2.Key([]byte(password), []byte(salt), 10000, 50, sha256.New)
  98. return fmt.Sprintf("%x", newPasswd)
  99. }
  100. // ValidatePassword returns true if the given password matches the encoded
  101. // version with given salt.
  102. func ValidatePassword(encoded, salt, password string) bool {
  103. got := EncodePassword(password, salt)
  104. return subtle.ConstantTimeCompare([]byte(encoded), []byte(got)) == 1
  105. }