Skip to content

Commit 620410c

Browse files
committed
Allow specifying SECRET_KEY_URI, similar to INTERNAL_TOKEN_URI
This modifies the existing internal token loading and the new secret key loading such that: * Specifying both INTERNAL_TOKEN and INTERNAL_TOKEN_URI is an error, instead of just preferring the URI * The install lock isn't required to regenerate the internal token or the secret key; it will always be regenerated if it's absent
1 parent 77c916f commit 620410c

File tree

2 files changed

+64
-32
lines changed

2 files changed

+64
-32
lines changed

custom/conf/app.example.ini

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -385,8 +385,11 @@ SECRET_KEY =
385385
;; Secret used to validate communication within Gitea binary.
386386
INTERNAL_TOKEN=
387387
;;
388-
;; Instead of defining internal token in the configuration, this configuration option can be used to give Gitea a path to a file that contains the internal token (example value: file:/etc/gitea/internal_token)
389-
;INTERNAL_TOKEN_URI = ;e.g. /etc/gitea/internal_token
388+
;; Alternative location to specify secret key, instead of this file; you cannot specify both this and SECRET_KEY, and must pick one
389+
;SECRET_KEY_URI = file:/etc/gitea/secret_key
390+
;;
391+
;; Alternative location to specify internal token, instead of this file; you cannot specify both this and INTERNAL_TOKEN, and must pick one
392+
;INTERNAL_TOKEN_URI = file:/etc/gitea/internal_token
390393
;;
391394
;; How long to remember that a user is logged in before requiring relogin (in days)
392395
;LOGIN_REMEMBER_DAYS = 7

modules/setting/setting.go

Lines changed: 59 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -921,9 +921,16 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
921921

922922
sec = Cfg.Section("security")
923923
InstallLock = sec.Key("INSTALL_LOCK").MustBool(false)
924-
SecretKey = sec.Key("SECRET_KEY").MustString("!#@FDEWREWR&*(")
925924
LogInRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt(7)
926925
CookieUserName = sec.Key("COOKIE_USERNAME").MustString("gitea_awesome")
926+
SecretKey = loadSecret(sec, "SECRET_KEY_URI", "SECRET_KEY", func() (string, error) {
927+
// FIXME: https://github.com/go-gitea/gitea/issues/16832
928+
//
929+
// Until we properly support rotating an existing secret key,
930+
// we shouldn't move users off of the default value
931+
return "!#@FDEWREWR&*(", nil
932+
})
933+
927934
CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").MustString("gitea_incredible")
928935

929936
ReverseProxyAuthUser = sec.Key("REVERSE_PROXY_AUTHENTICATION_USER").MustString("X-WEBAUTH-USER")
@@ -946,11 +953,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
946953
PasswordCheckPwn = sec.Key("PASSWORD_CHECK_PWN").MustBool(false)
947954
SuccessfulTokensCacheSize = sec.Key("SUCCESSFUL_TOKENS_CACHE_SIZE").MustInt(20)
948955

949-
InternalToken = loadInternalToken(sec)
950-
if InstallLock && InternalToken == "" {
951-
// if Gitea has been installed but the InternalToken hasn't been generated (upgrade from an old release), we should generate
952-
generateSaveInternalToken()
953-
}
956+
InternalToken = loadSecret(sec, "INTERNAL_TOKEN_URI", "INTERNAL_TOKEN", generate.NewInternalToken)
954957

955958
cfgdata := sec.Key("PASSWORD_COMPLEXITY").Strings(",")
956959
if len(cfgdata) == 0 {
@@ -1139,51 +1142,73 @@ func parseAuthorizedPrincipalsAllow(values []string) ([]string, bool) {
11391142
return authorizedPrincipalsAllow, true
11401143
}
11411144

1142-
func loadInternalToken(sec *ini.Section) string {
1143-
uri := sec.Key("INTERNAL_TOKEN_URI").String()
1145+
func loadSecret(
1146+
sec *ini.Section,
1147+
uriKey string,
1148+
verbatimKey string,
1149+
generator func() (string, error),
1150+
) string {
1151+
// don't allow setting both URI and verbatim string
1152+
uri := sec.Key(uriKey).String()
1153+
verbatim := sec.Key(verbatimKey).String()
1154+
if uri != "" && verbatim != "" {
1155+
log.Fatal("Cannot specify both %s and %s", uriKey, verbatimKey)
1156+
}
1157+
1158+
// if we have no URI, use verbatim
11441159
if uri == "" {
1145-
return sec.Key("INTERNAL_TOKEN").String()
1160+
// if verbatim isn't provided, generate one
1161+
if verbatim == "" {
1162+
secret, err := generator()
1163+
if err != nil {
1164+
log.Fatal("Error trying to generate %s: %v", verbatimKey, err)
1165+
}
1166+
CreateOrAppendToCustomConf(func(cfg *ini.File) {
1167+
cfg.Section(sec.Name()).Key(verbatimKey).SetValue(secret)
1168+
})
1169+
return secret
1170+
}
1171+
1172+
return verbatim
11461173
}
1174+
11471175
tempURI, err := url.Parse(uri)
11481176
if err != nil {
1149-
log.Fatal("Failed to parse INTERNAL_TOKEN_URI (%s): %v", uri, err)
1177+
log.Fatal("Failed to parse %s (%s): %v", uriKey, uri, err)
11501178
}
11511179
switch tempURI.Scheme {
11521180
case "file":
11531181
buf, err := os.ReadFile(tempURI.RequestURI())
11541182
if err != nil && !os.IsNotExist(err) {
1155-
log.Fatal("Failed to open InternalTokenURI (%s): %v", uri, err)
1183+
log.Fatal("Failed to open %s (%s): %v", uriKey, uri, err)
11561184
}
1157-
// No token in the file, generate one and store it.
1185+
1186+
// empty file; generate secret and store it
11581187
if len(buf) == 0 {
1159-
token, err := generate.NewInternalToken()
1188+
token, err := generator()
11601189
if err != nil {
1161-
log.Fatal("Error generate internal token: %v", err)
1190+
log.Fatal("Error generating %s: %v", verbatimKey, err)
11621191
}
1192+
11631193
err = os.WriteFile(tempURI.RequestURI(), []byte(token), 0o600)
11641194
if err != nil {
1165-
log.Fatal("Error writing to InternalTokenURI (%s): %v", uri, err)
1195+
log.Fatal("Error writing to %s (%s): %v", uriKey, uri, err)
11661196
}
1197+
1198+
// we assume generator gives pre-parsed token
11671199
return token
11681200
}
1201+
11691202
return strings.TrimSpace(string(buf))
1203+
1204+
// only file URIs are allowed
11701205
default:
11711206
log.Fatal("Unsupported URI-Scheme %q (INTERNAL_TOKEN_URI = %q)", tempURI.Scheme, uri)
11721207
}
1173-
return ""
1174-
}
11751208

1176-
// generateSaveInternalToken generates and saves the internal token to app.ini
1177-
func generateSaveInternalToken() {
1178-
token, err := generate.NewInternalToken()
1179-
if err != nil {
1180-
log.Fatal("Error generate internal token: %v", err)
1181-
}
1182-
1183-
InternalToken = token
1184-
CreateOrAppendToCustomConf(func(cfg *ini.File) {
1185-
cfg.Section("security").Key("INTERNAL_TOKEN").SetValue(token)
1186-
})
1209+
// we should never get here
1210+
log.Fatal("Unknown error when loading %s", verbatimKey)
1211+
return ""
11871212
}
11881213

11891214
// MakeAbsoluteAssetURL returns the absolute asset url prefix without a trailing slash
@@ -1248,6 +1273,11 @@ func MakeManifestData(appName, appURL, absoluteAssetURL string) []byte {
12481273
// CreateOrAppendToCustomConf creates or updates the custom config.
12491274
// Use the callback to set individual values.
12501275
func CreateOrAppendToCustomConf(callback func(cfg *ini.File)) {
1276+
if CustomConf == "" {
1277+
log.Error("Custom config path must not be empty")
1278+
return
1279+
}
1280+
12511281
cfg := ini.Empty()
12521282
isFile, err := util.IsFile(CustomConf)
12531283
if err != nil {
@@ -1262,15 +1292,14 @@ func CreateOrAppendToCustomConf(callback func(cfg *ini.File)) {
12621292

12631293
callback(cfg)
12641294

1265-
log.Info("Settings saved to: %q", CustomConf)
1266-
12671295
if err := os.MkdirAll(filepath.Dir(CustomConf), os.ModePerm); err != nil {
12681296
log.Fatal("failed to create '%s': %v", CustomConf, err)
12691297
return
12701298
}
12711299
if err := cfg.SaveTo(CustomConf); err != nil {
12721300
log.Fatal("error saving to custom config: %v", err)
12731301
}
1302+
log.Info("Settings saved to: %q", CustomConf)
12741303

12751304
// Change permissions to be more restrictive
12761305
fi, err := os.Stat(CustomConf)

0 commit comments

Comments
 (0)