4
4
package setting
5
5
6
6
import (
7
- "encoding/base64"
8
7
"math"
9
8
"path/filepath"
9
+ "sync/atomic"
10
10
11
11
"code.gitea.io/gitea/modules/generate"
12
12
"code.gitea.io/gitea/modules/log"
13
- "code.gitea.io/gitea/modules/util"
14
13
)
15
14
16
15
// OAuth2UsernameType is enum describing the way gitea 'name' should be generated from oauth2 data
@@ -98,7 +97,6 @@ var OAuth2 = struct {
98
97
RefreshTokenExpirationTime int64
99
98
InvalidateRefreshTokens bool
100
99
JWTSigningAlgorithm string `ini:"JWT_SIGNING_ALGORITHM"`
101
- JWTSecretBase64 string `ini:"JWT_SECRET"`
102
100
JWTSigningPrivateKeyFile string `ini:"JWT_SIGNING_PRIVATE_KEY_FILE"`
103
101
MaxTokenLength int
104
102
DefaultApplications []string
@@ -123,29 +121,50 @@ func loadOAuth2From(rootCfg ConfigProvider) {
123
121
return
124
122
}
125
123
126
- OAuth2 . JWTSecretBase64 = loadSecret (rootCfg .Section ("oauth2" ), "JWT_SECRET_URI" , "JWT_SECRET" )
124
+ jwtSecretBase64 : = loadSecret (rootCfg .Section ("oauth2" ), "JWT_SECRET_URI" , "JWT_SECRET" )
127
125
128
126
if ! filepath .IsAbs (OAuth2 .JWTSigningPrivateKeyFile ) {
129
127
OAuth2 .JWTSigningPrivateKeyFile = filepath .Join (AppDataPath , OAuth2 .JWTSigningPrivateKeyFile )
130
128
}
131
129
132
130
if InstallLock {
133
- if _ , err := util .Base64FixedDecode (base64 .RawURLEncoding , []byte (OAuth2 .JWTSecretBase64 ), 32 ); err != nil {
134
- key , err := generate .NewJwtSecret ()
131
+ jwtSecretBytes , err := generate .DecodeJwtSecretBase64 (jwtSecretBase64 )
132
+ if err != nil {
133
+ jwtSecretBytes , jwtSecretBase64 , err = generate .NewJwtSecretWithBase64 ()
135
134
if err != nil {
136
135
log .Fatal ("error generating JWT secret: %v" , err )
137
136
}
138
-
139
- OAuth2 .JWTSecretBase64 = base64 .RawURLEncoding .EncodeToString (key )
140
137
saveCfg , err := rootCfg .PrepareSaving ()
141
138
if err != nil {
142
139
log .Fatal ("save oauth2.JWT_SECRET failed: %v" , err )
143
140
}
144
- rootCfg .Section ("oauth2" ).Key ("JWT_SECRET" ).SetValue (OAuth2 . JWTSecretBase64 )
145
- saveCfg .Section ("oauth2" ).Key ("JWT_SECRET" ).SetValue (OAuth2 . JWTSecretBase64 )
141
+ rootCfg .Section ("oauth2" ).Key ("JWT_SECRET" ).SetValue (jwtSecretBase64 )
142
+ saveCfg .Section ("oauth2" ).Key ("JWT_SECRET" ).SetValue (jwtSecretBase64 )
146
143
if err := saveCfg .Save (); err != nil {
147
144
log .Fatal ("save oauth2.JWT_SECRET failed: %v" , err )
148
145
}
149
146
}
147
+ generalSigningSecret .Store (& jwtSecretBytes )
148
+ }
149
+ }
150
+
151
+ // generalSigningSecret is used as container for a []byte value
152
+ // instead of an additional mutex, we use CompareAndSwap func to change the value thread save
153
+ var generalSigningSecret atomic.Pointer [[]byte ]
154
+
155
+ func GetGeneralTokenSigningSecret () []byte {
156
+ old := generalSigningSecret .Load ()
157
+ if old == nil || len (* old ) == 0 {
158
+ jwtSecret , _ , err := generate .NewJwtSecretWithBase64 ()
159
+ if err != nil {
160
+ log .Fatal ("Unable to generate general JWT secret: %s" , err .Error ())
161
+ }
162
+ if generalSigningSecret .CompareAndSwap (old , & jwtSecret ) {
163
+ // FIXME: in main branch, the signing token should be refactored (eg: one unique for LFS/OAuth2/etc ...)
164
+ log .Warn ("OAuth2 is not enabled, unable to use a persistent signing secret, a new one is generated, which is not persistent between restarts and cluster nodes" )
165
+ return jwtSecret
166
+ }
167
+ return * generalSigningSecret .Load ()
150
168
}
169
+ return * old
151
170
}
0 commit comments