@@ -5,18 +5,20 @@ package avatars
5
5
6
6
import (
7
7
"context"
8
+ "fmt"
8
9
"net/url"
9
10
"path"
10
11
"strconv"
11
12
"strings"
12
- "sync"
13
+ "sync/atomic "
13
14
14
15
"code.gitea.io/gitea/models/db"
15
- system_model "code.gitea.io/gitea/models/system"
16
16
"code.gitea.io/gitea/modules/base"
17
17
"code.gitea.io/gitea/modules/cache"
18
18
"code.gitea.io/gitea/modules/log"
19
19
"code.gitea.io/gitea/modules/setting"
20
+
21
+ "strk.kbt.io/projects/go/libravatar"
20
22
)
21
23
22
24
const (
@@ -36,24 +38,54 @@ func init() {
36
38
db .RegisterModel (new (EmailHash ))
37
39
}
38
40
39
- var (
41
+ type avatarSettingStruct struct {
40
42
defaultAvatarLink string
41
- once sync.Once
42
- )
43
+ gravatarSource string
44
+ gravatarSourceURL * url.URL
45
+ libravatar * libravatar.Libravatar
46
+ }
43
47
44
- // DefaultAvatarLink the default avatar link
45
- func DefaultAvatarLink () string {
46
- once .Do (func () {
48
+ var avatarSettingAtomic atomic.Pointer [avatarSettingStruct ]
49
+
50
+ func loadAvatarSetting () (* avatarSettingStruct , error ) {
51
+ s := avatarSettingAtomic .Load ()
52
+ if s == nil || s .gravatarSource != setting .GravatarSource {
53
+ s = & avatarSettingStruct {}
47
54
u , err := url .Parse (setting .AppSubURL )
48
55
if err != nil {
49
- log .Error ("Can not parse AppSubURL: %v" , err )
50
- return
56
+ return nil , fmt .Errorf ("unable to parse AppSubURL: %w" , err )
51
57
}
52
58
53
59
u .Path = path .Join (u .Path , "/assets/img/avatar_default.png" )
54
- defaultAvatarLink = u .String ()
55
- })
56
- return defaultAvatarLink
60
+ s .defaultAvatarLink = u .String ()
61
+
62
+ s .gravatarSourceURL , err = url .Parse (setting .GravatarSource )
63
+ if err != nil {
64
+ return nil , fmt .Errorf ("unable to parse GravatarSource %q: %w" , setting .GravatarSource , err )
65
+ }
66
+
67
+ s .libravatar = libravatar .New ()
68
+ if s .gravatarSourceURL .Scheme == "https" {
69
+ s .libravatar .SetUseHTTPS (true )
70
+ s .libravatar .SetSecureFallbackHost (s .gravatarSourceURL .Host )
71
+ } else {
72
+ s .libravatar .SetUseHTTPS (false )
73
+ s .libravatar .SetFallbackHost (s .gravatarSourceURL .Host )
74
+ }
75
+
76
+ avatarSettingAtomic .Store (s )
77
+ }
78
+ return s , nil
79
+ }
80
+
81
+ // DefaultAvatarLink the default avatar link
82
+ func DefaultAvatarLink () string {
83
+ a , err := loadAvatarSetting ()
84
+ if err != nil {
85
+ log .Error ("Failed to loadAvatarSetting: %v" , err )
86
+ return ""
87
+ }
88
+ return a .defaultAvatarLink
57
89
}
58
90
59
91
// HashEmail hashes email address to MD5 string. https://en.gravatar.com/site/implement/hash/
@@ -76,7 +108,11 @@ func GetEmailForHash(md5Sum string) (string, error) {
76
108
// LibravatarURL returns the URL for the given email. Slow due to the DNS lookup.
77
109
// This function should only be called if a federated avatar service is enabled.
78
110
func LibravatarURL (email string ) (* url.URL , error ) {
79
- urlStr , err := system_model .LibravatarService .FromEmail (email )
111
+ a , err := loadAvatarSetting ()
112
+ if err != nil {
113
+ return nil , err
114
+ }
115
+ urlStr , err := a .libravatar .FromEmail (email )
80
116
if err != nil {
81
117
log .Error ("LibravatarService.FromEmail(email=%s): error %v" , email , err )
82
118
return nil , err
@@ -153,15 +189,13 @@ func generateEmailAvatarLink(ctx context.Context, email string, size int, final
153
189
return DefaultAvatarLink ()
154
190
}
155
191
156
- disableGravatar := system_model .GetSettingWithCacheBool (ctx , system_model .KeyPictureDisableGravatar ,
157
- setting .GetDefaultDisableGravatar (),
158
- )
159
-
160
- enableFederatedAvatar := system_model .GetSettingWithCacheBool (ctx , system_model .KeyPictureEnableFederatedAvatar ,
161
- setting .GetDefaultEnableFederatedAvatar (disableGravatar ))
192
+ avatarSetting , err := loadAvatarSetting ()
193
+ if err != nil {
194
+ return DefaultAvatarLink ()
195
+ }
162
196
163
- var err error
164
- if enableFederatedAvatar && system_model . LibravatarService != nil {
197
+ enableFederatedAvatar := setting . Config (). Picture . EnableFederatedAvatar . Value ( ctx )
198
+ if enableFederatedAvatar {
165
199
emailHash := saveEmailHash (email )
166
200
if final {
167
201
// for final link, we can spend more time on slow external query
@@ -179,9 +213,10 @@ func generateEmailAvatarLink(ctx context.Context, email string, size int, final
179
213
return urlStr
180
214
}
181
215
216
+ disableGravatar := setting .Config ().Picture .DisableGravatar .Value (ctx )
182
217
if ! disableGravatar {
183
218
// copy GravatarSourceURL, because we will modify its Path.
184
- avatarURLCopy := * system_model . GravatarSourceURL
219
+ avatarURLCopy := * avatarSetting . gravatarSourceURL
185
220
avatarURLCopy .Path = path .Join (avatarURLCopy .Path , HashEmail (email ))
186
221
return generateRecognizedAvatarURL (avatarURLCopy , size )
187
222
}
0 commit comments