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