44package setting
55
66import (
7- "encoding/base64"
87 "math"
98 "path/filepath"
9+ "sync/atomic"
1010
1111 "code.gitea.io/gitea/modules/generate"
1212 "code.gitea.io/gitea/modules/log"
13- "code.gitea.io/gitea/modules/util"
1413)
1514
1615// OAuth2UsernameType is enum describing the way gitea 'name' should be generated from oauth2 data
@@ -98,7 +97,6 @@ var OAuth2 = struct {
9897 RefreshTokenExpirationTime int64
9998 InvalidateRefreshTokens bool
10099 JWTSigningAlgorithm string `ini:"JWT_SIGNING_ALGORITHM"`
101- JWTSecretBase64 string `ini:"JWT_SECRET"`
102100 JWTSigningPrivateKeyFile string `ini:"JWT_SIGNING_PRIVATE_KEY_FILE"`
103101 MaxTokenLength int
104102 DefaultApplications []string
@@ -123,29 +121,50 @@ func loadOAuth2From(rootCfg ConfigProvider) {
123121 return
124122 }
125123
126- OAuth2 . JWTSecretBase64 = loadSecret (rootCfg .Section ("oauth2" ), "JWT_SECRET_URI" , "JWT_SECRET" )
124+ jwtSecretBase64 : = loadSecret (rootCfg .Section ("oauth2" ), "JWT_SECRET_URI" , "JWT_SECRET" )
127125
128126 if ! filepath .IsAbs (OAuth2 .JWTSigningPrivateKeyFile ) {
129127 OAuth2 .JWTSigningPrivateKeyFile = filepath .Join (AppDataPath , OAuth2 .JWTSigningPrivateKeyFile )
130128 }
131129
132130 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 ()
135134 if err != nil {
136135 log .Fatal ("error generating JWT secret: %v" , err )
137136 }
138-
139- OAuth2 .JWTSecretBase64 = base64 .RawURLEncoding .EncodeToString (key )
140137 saveCfg , err := rootCfg .PrepareSaving ()
141138 if err != nil {
142139 log .Fatal ("save oauth2.JWT_SECRET failed: %v" , err )
143140 }
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 )
146143 if err := saveCfg .Save (); err != nil {
147144 log .Fatal ("save oauth2.JWT_SECRET failed: %v" , err )
148145 }
149146 }
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 ()
150168 }
169+ return * old
151170}
0 commit comments