From 4d1e2b8334b6f18b82ef4e646dd122200fb0b6c3 Mon Sep 17 00:00:00 2001
From: wxiaoguang <wxiaoguang@gmail.com>
Date: Fri, 4 Nov 2022 04:55:09 +0800
Subject: [PATCH] Fix token generation when using INTERNAL_TOKEN_URI (#21669)

Fix https://github.com/go-gitea/gitea/issues/21666
Caused by https://github.com/go-gitea/gitea/pull/19663

Before: when install, the INTERNAL_TOKEN was always generated and saved.
But the internal token may be already there by INTERNAL_TOKEN_URI

After: INTERNAL_TOKEN_URI file must be non-empty. When install, skip
internal token generation if the token exists.
---
 modules/setting/setting.go | 12 +++++++++++-
 routers/install/install.go | 14 +++++++++-----
 2 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/modules/setting/setting.go b/modules/setting/setting.go
index 043acb733d..2e5bb17b6a 100644
--- a/modules/setting/setting.go
+++ b/modules/setting/setting.go
@@ -1158,6 +1158,8 @@ func parseAuthorizedPrincipalsAllow(values []string) ([]string, bool) {
 	return authorizedPrincipalsAllow, true
 }
 
+// loadSecret load the secret from ini by uriKey or verbatimKey, only one of them could be set
+// If the secret is loaded from uriKey (file), the file should be non-empty, to guarantee the behavior stable and clear.
 func loadSecret(sec *ini.Section, uriKey, verbatimKey string) string {
 	// don't allow setting both URI and verbatim string
 	uri := sec.Key(uriKey).String()
@@ -1181,7 +1183,15 @@ func loadSecret(sec *ini.Section, uriKey, verbatimKey string) string {
 		if err != nil {
 			log.Fatal("Failed to read %s (%s): %v", uriKey, tempURI.RequestURI(), err)
 		}
-		return strings.TrimSpace(string(buf))
+		val := strings.TrimSpace(string(buf))
+		if val == "" {
+			// The file shouldn't be empty, otherwise we can not know whether the user has ever set the KEY or KEY_URI
+			// For example: if INTERNAL_TOKEN_URI=file:///empty-file,
+			// Then if the token is re-generated during installation and saved to INTERNAL_TOKEN
+			// Then INTERNAL_TOKEN and INTERNAL_TOKEN_URI both exist, that's a fatal error (they shouldn't)
+			log.Fatal("Failed to read %s (%s): the file is empty", uriKey, tempURI.RequestURI())
+		}
+		return val
 
 	// only file URIs are allowed
 	default:
diff --git a/routers/install/install.go b/routers/install/install.go
index 6bac5b5ff7..184dc5bae1 100644
--- a/routers/install/install.go
+++ b/routers/install/install.go
@@ -474,12 +474,16 @@ func SubmitInstall(ctx *context.Context) {
 
 	cfg.Section("security").Key("INSTALL_LOCK").SetValue("true")
 
-	var internalToken string
-	if internalToken, err = generate.NewInternalToken(); err != nil {
-		ctx.RenderWithErr(ctx.Tr("install.internal_token_failed", err), tplInstall, &form)
-		return
+	// the internal token could be read from INTERNAL_TOKEN or INTERNAL_TOKEN_URI (the file is guaranteed to be non-empty)
+	// if there is no InternalToken, generate one and save to security.INTERNAL_TOKEN
+	if setting.InternalToken == "" {
+		var internalToken string
+		if internalToken, err = generate.NewInternalToken(); err != nil {
+			ctx.RenderWithErr(ctx.Tr("install.internal_token_failed", err), tplInstall, &form)
+			return
+		}
+		cfg.Section("security").Key("INTERNAL_TOKEN").SetValue(internalToken)
 	}
-	cfg.Section("security").Key("INTERNAL_TOKEN").SetValue(internalToken)
 
 	// if there is already a SECRET_KEY, we should not overwrite it, otherwise the encrypted data will not be able to be decrypted
 	if setting.SecretKey == "" {