mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	Refactor the setting to make unit test easier (#22405)
Some bugs caused by less unit tests in fundamental packages. This PR refactor `setting` package so that create a unit test will be easier than before. - All `LoadFromXXX` files has been splited as two functions, one is `InitProviderFromXXX` and `LoadCommonSettings`. The first functions will only include the code to create or new a ini file. The second function will load common settings. - It also renames all functions in setting from `newXXXService` to `loadXXXSetting` or `loadXXXFrom` to make the function name less confusing. - Move `XORMLog` to `SQLLog` because it's a better name for that. Maybe we should finally move these `loadXXXSetting` into the `XXXInit` function? Any idea? --------- Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: delvh <dev.lh@web.de>
This commit is contained in:
		@@ -57,9 +57,10 @@ func confirm() (bool, error) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func initDB(ctx context.Context) error {
 | 
					func initDB(ctx context.Context) error {
 | 
				
			||||||
	setting.LoadFromExisting()
 | 
						setting.InitProviderFromExistingFile()
 | 
				
			||||||
	setting.InitDBConfig()
 | 
						setting.LoadCommonSettings()
 | 
				
			||||||
	setting.NewXORMLogService(false)
 | 
						setting.LoadDBSetting()
 | 
				
			||||||
 | 
						setting.InitSQLLog(false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if setting.Database.Type == "" {
 | 
						if setting.Database.Type == "" {
 | 
				
			||||||
		log.Fatal(`Database settings are missing from the configuration file: %q.
 | 
							log.Fatal(`Database settings are missing from the configuration file: %q.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,7 +32,7 @@ func runConvert(ctx *cli.Context) error {
 | 
				
			|||||||
	log.Info("AppPath: %s", setting.AppPath)
 | 
						log.Info("AppPath: %s", setting.AppPath)
 | 
				
			||||||
	log.Info("AppWorkPath: %s", setting.AppWorkPath)
 | 
						log.Info("AppWorkPath: %s", setting.AppWorkPath)
 | 
				
			||||||
	log.Info("Custom path: %s", setting.CustomPath)
 | 
						log.Info("Custom path: %s", setting.CustomPath)
 | 
				
			||||||
	log.Info("Log path: %s", setting.LogRootPath)
 | 
						log.Info("Log path: %s", setting.Log.RootPath)
 | 
				
			||||||
	log.Info("Configuration file: %s", setting.CustomConf)
 | 
						log.Info("Configuration file: %s", setting.CustomConf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if !setting.Database.UseMySQL {
 | 
						if !setting.Database.UseMySQL {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -87,14 +87,16 @@ func runRecreateTable(ctx *cli.Context) error {
 | 
				
			|||||||
	golog.SetPrefix("")
 | 
						golog.SetPrefix("")
 | 
				
			||||||
	golog.SetOutput(log.NewLoggerAsWriter("INFO", log.GetLogger(log.DEFAULT)))
 | 
						golog.SetOutput(log.NewLoggerAsWriter("INFO", log.GetLogger(log.DEFAULT)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setting.LoadFromExisting()
 | 
						setting.InitProviderFromExistingFile()
 | 
				
			||||||
	setting.InitDBConfig()
 | 
						setting.LoadCommonSettings()
 | 
				
			||||||
 | 
						setting.LoadDBSetting()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setting.EnableXORMLog = ctx.Bool("debug")
 | 
						setting.Log.EnableXORMLog = ctx.Bool("debug")
 | 
				
			||||||
	setting.Database.LogSQL = ctx.Bool("debug")
 | 
						setting.Database.LogSQL = ctx.Bool("debug")
 | 
				
			||||||
	setting.Cfg.Section("log").Key("XORM").SetValue(",")
 | 
						// FIXME: don't use CfgProvider directly
 | 
				
			||||||
 | 
						setting.CfgProvider.Section("log").Key("XORM").SetValue(",")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setting.NewXORMLogService(!ctx.Bool("debug"))
 | 
						setting.InitSQLLog(!ctx.Bool("debug"))
 | 
				
			||||||
	stdCtx, cancel := installSignals()
 | 
						stdCtx, cancel := installSignals()
 | 
				
			||||||
	defer cancel()
 | 
						defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										20
									
								
								cmd/dump.go
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								cmd/dump.go
									
									
									
									
									
								
							@@ -181,20 +181,22 @@ func runDump(ctx *cli.Context) error {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		fileName += "." + outType
 | 
							fileName += "." + outType
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	setting.LoadFromExisting()
 | 
						setting.InitProviderFromExistingFile()
 | 
				
			||||||
 | 
						setting.LoadCommonSettings()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// make sure we are logging to the console no matter what the configuration tells us do to
 | 
						// make sure we are logging to the console no matter what the configuration tells us do to
 | 
				
			||||||
	if _, err := setting.Cfg.Section("log").NewKey("MODE", "console"); err != nil {
 | 
						// FIXME: don't use CfgProvider directly
 | 
				
			||||||
 | 
						if _, err := setting.CfgProvider.Section("log").NewKey("MODE", "console"); err != nil {
 | 
				
			||||||
		fatal("Setting logging mode to console failed: %v", err)
 | 
							fatal("Setting logging mode to console failed: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if _, err := setting.Cfg.Section("log.console").NewKey("STDERR", "true"); err != nil {
 | 
						if _, err := setting.CfgProvider.Section("log.console").NewKey("STDERR", "true"); err != nil {
 | 
				
			||||||
		fatal("Setting console logger to stderr failed: %v", err)
 | 
							fatal("Setting console logger to stderr failed: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !setting.InstallLock {
 | 
						if !setting.InstallLock {
 | 
				
			||||||
		log.Error("Is '%s' really the right config path?\n", setting.CustomConf)
 | 
							log.Error("Is '%s' really the right config path?\n", setting.CustomConf)
 | 
				
			||||||
		return fmt.Errorf("gitea is not initialized")
 | 
							return fmt.Errorf("gitea is not initialized")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	setting.NewServices() // cannot access session settings otherwise
 | 
						setting.LoadSettings() // cannot access session settings otherwise
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stdCtx, cancel := installSignals()
 | 
						stdCtx, cancel := installSignals()
 | 
				
			||||||
	defer cancel()
 | 
						defer cancel()
 | 
				
			||||||
@@ -322,7 +324,7 @@ func runDump(ctx *cli.Context) error {
 | 
				
			|||||||
		log.Info("Packing data directory...%s", setting.AppDataPath)
 | 
							log.Info("Packing data directory...%s", setting.AppDataPath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		var excludes []string
 | 
							var excludes []string
 | 
				
			||||||
		if setting.Cfg.Section("session").Key("PROVIDER").Value() == "file" {
 | 
							if setting.SessionConfig.OriginalProvider == "file" {
 | 
				
			||||||
			var opts session.Options
 | 
								var opts session.Options
 | 
				
			||||||
			if err = json.Unmarshal([]byte(setting.SessionConfig.ProviderConfig), &opts); err != nil {
 | 
								if err = json.Unmarshal([]byte(setting.SessionConfig.ProviderConfig), &opts); err != nil {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
@@ -339,7 +341,7 @@ func runDump(ctx *cli.Context) error {
 | 
				
			|||||||
		excludes = append(excludes, setting.LFS.Path)
 | 
							excludes = append(excludes, setting.LFS.Path)
 | 
				
			||||||
		excludes = append(excludes, setting.Attachment.Path)
 | 
							excludes = append(excludes, setting.Attachment.Path)
 | 
				
			||||||
		excludes = append(excludes, setting.Packages.Path)
 | 
							excludes = append(excludes, setting.Packages.Path)
 | 
				
			||||||
		excludes = append(excludes, setting.LogRootPath)
 | 
							excludes = append(excludes, setting.Log.RootPath)
 | 
				
			||||||
		excludes = append(excludes, absFileName)
 | 
							excludes = append(excludes, absFileName)
 | 
				
			||||||
		if err := addRecursiveExclude(w, "data", setting.AppDataPath, excludes, verbose); err != nil {
 | 
							if err := addRecursiveExclude(w, "data", setting.AppDataPath, excludes, verbose); err != nil {
 | 
				
			||||||
			fatal("Failed to include data directory: %v", err)
 | 
								fatal("Failed to include data directory: %v", err)
 | 
				
			||||||
@@ -378,12 +380,12 @@ func runDump(ctx *cli.Context) error {
 | 
				
			|||||||
	if ctx.IsSet("skip-log") && ctx.Bool("skip-log") {
 | 
						if ctx.IsSet("skip-log") && ctx.Bool("skip-log") {
 | 
				
			||||||
		log.Info("Skip dumping log files")
 | 
							log.Info("Skip dumping log files")
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		isExist, err := util.IsExist(setting.LogRootPath)
 | 
							isExist, err := util.IsExist(setting.Log.RootPath)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			log.Error("Unable to check if %s exists. Error: %v", setting.LogRootPath, err)
 | 
								log.Error("Unable to check if %s exists. Error: %v", setting.Log.RootPath, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if isExist {
 | 
							if isExist {
 | 
				
			||||||
			if err := addRecursiveExclude(w, "log", setting.LogRootPath, []string{absFileName}, verbose); err != nil {
 | 
								if err := addRecursiveExclude(w, "log", setting.Log.RootPath, []string{absFileName}, verbose); err != nil {
 | 
				
			||||||
				fatal("Failed to include log: %v", err)
 | 
									fatal("Failed to include log: %v", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -94,7 +94,7 @@ func runDumpRepository(ctx *cli.Context) error {
 | 
				
			|||||||
	log.Info("AppPath: %s", setting.AppPath)
 | 
						log.Info("AppPath: %s", setting.AppPath)
 | 
				
			||||||
	log.Info("AppWorkPath: %s", setting.AppWorkPath)
 | 
						log.Info("AppWorkPath: %s", setting.AppWorkPath)
 | 
				
			||||||
	log.Info("Custom path: %s", setting.CustomPath)
 | 
						log.Info("Custom path: %s", setting.CustomPath)
 | 
				
			||||||
	log.Info("Log path: %s", setting.LogRootPath)
 | 
						log.Info("Log path: %s", setting.Log.RootPath)
 | 
				
			||||||
	log.Info("Configuration file: %s", setting.CustomConf)
 | 
						log.Info("Configuration file: %s", setting.CustomConf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -112,7 +112,8 @@ func initEmbeddedExtractor(c *cli.Context) error {
 | 
				
			|||||||
	log.DelNamedLogger(log.DEFAULT)
 | 
						log.DelNamedLogger(log.DEFAULT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Read configuration file
 | 
						// Read configuration file
 | 
				
			||||||
	setting.LoadAllowEmpty()
 | 
						setting.InitProviderAllowEmpty()
 | 
				
			||||||
 | 
						setting.LoadCommonSettings()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pats, err := getPatterns(c.Args())
 | 
						pats, err := getPatterns(c.Args())
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,7 +17,8 @@ func runSendMail(c *cli.Context) error {
 | 
				
			|||||||
	ctx, cancel := installSignals()
 | 
						ctx, cancel := installSignals()
 | 
				
			||||||
	defer cancel()
 | 
						defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setting.LoadFromExisting()
 | 
						setting.InitProviderFromExistingFile()
 | 
				
			||||||
 | 
						setting.LoadCommonSettings()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := argsSet(c, "title"); err != nil {
 | 
						if err := argsSet(c, "title"); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
	setting.SetCustomPathAndConf("", "", "")
 | 
						setting.SetCustomPathAndConf("", "", "")
 | 
				
			||||||
	setting.LoadForTest()
 | 
						setting.InitProviderAndLoadCommonSettingsForTest()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestMain(m *testing.M) {
 | 
					func TestMain(m *testing.M) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,7 +33,7 @@ func runMigrate(ctx *cli.Context) error {
 | 
				
			|||||||
	log.Info("AppPath: %s", setting.AppPath)
 | 
						log.Info("AppPath: %s", setting.AppPath)
 | 
				
			||||||
	log.Info("AppWorkPath: %s", setting.AppWorkPath)
 | 
						log.Info("AppWorkPath: %s", setting.AppWorkPath)
 | 
				
			||||||
	log.Info("Custom path: %s", setting.CustomPath)
 | 
						log.Info("Custom path: %s", setting.CustomPath)
 | 
				
			||||||
	log.Info("Log path: %s", setting.LogRootPath)
 | 
						log.Info("Log path: %s", setting.Log.RootPath)
 | 
				
			||||||
	log.Info("Configuration file: %s", setting.CustomConf)
 | 
						log.Info("Configuration file: %s", setting.CustomConf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := db.InitEngineWithMigration(context.Background(), migrations.Migrate); err != nil {
 | 
						if err := db.InitEngineWithMigration(context.Background(), migrations.Migrate); err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -136,7 +136,7 @@ func runMigrateStorage(ctx *cli.Context) error {
 | 
				
			|||||||
	log.Info("AppPath: %s", setting.AppPath)
 | 
						log.Info("AppPath: %s", setting.AppPath)
 | 
				
			||||||
	log.Info("AppWorkPath: %s", setting.AppWorkPath)
 | 
						log.Info("AppWorkPath: %s", setting.AppWorkPath)
 | 
				
			||||||
	log.Info("Custom path: %s", setting.CustomPath)
 | 
						log.Info("Custom path: %s", setting.CustomPath)
 | 
				
			||||||
	log.Info("Log path: %s", setting.LogRootPath)
 | 
						log.Info("Log path: %s", setting.Log.RootPath)
 | 
				
			||||||
	log.Info("Configuration file: %s", setting.CustomConf)
 | 
						log.Info("Configuration file: %s", setting.CustomConf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := db.InitEngineWithMigration(context.Background(), migrations.Migrate); err != nil {
 | 
						if err := db.InitEngineWithMigration(context.Background(), migrations.Migrate); err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,7 +54,8 @@ func runRestoreRepository(c *cli.Context) error {
 | 
				
			|||||||
	ctx, cancel := installSignals()
 | 
						ctx, cancel := installSignals()
 | 
				
			||||||
	defer cancel()
 | 
						defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setting.LoadFromExisting()
 | 
						setting.InitProviderFromExistingFile()
 | 
				
			||||||
 | 
						setting.LoadCommonSettings()
 | 
				
			||||||
	var units []string
 | 
						var units []string
 | 
				
			||||||
	if s := c.String("units"); s != "" {
 | 
						if s := c.String("units"); s != "" {
 | 
				
			||||||
		units = strings.Split(s, ",")
 | 
							units = strings.Split(s, ",")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -61,7 +61,8 @@ func setup(logPath string, debug bool) {
 | 
				
			|||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		_ = log.NewLogger(1000, "console", "console", `{"level":"fatal","stacktracelevel":"NONE","stderr":true}`)
 | 
							_ = log.NewLogger(1000, "console", "console", `{"level":"fatal","stacktracelevel":"NONE","stderr":true}`)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	setting.LoadFromExisting()
 | 
						setting.InitProviderFromExistingFile()
 | 
				
			||||||
 | 
						setting.LoadCommonSettings()
 | 
				
			||||||
	if debug {
 | 
						if debug {
 | 
				
			||||||
		setting.RunMode = "dev"
 | 
							setting.RunMode = "dev"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -158,7 +158,8 @@ func runWeb(ctx *cli.Context) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	log.Info("Global init")
 | 
						log.Info("Global init")
 | 
				
			||||||
	// Perform global initialization
 | 
						// Perform global initialization
 | 
				
			||||||
	setting.LoadFromExisting()
 | 
						setting.InitProviderFromExistingFile()
 | 
				
			||||||
 | 
						setting.LoadCommonSettings()
 | 
				
			||||||
	routers.GlobalInitInstalled(graceful.GetManager().HammerContext())
 | 
						routers.GlobalInitInstalled(graceful.GetManager().HammerContext())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// We check that AppDataPath exists here (it should have been created during installation)
 | 
						// We check that AppDataPath exists here (it should have been created during installation)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -49,7 +49,8 @@ func runPR() {
 | 
				
			|||||||
		log.Fatal(err)
 | 
							log.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	setting.SetCustomPathAndConf("", "", "")
 | 
						setting.SetCustomPathAndConf("", "", "")
 | 
				
			||||||
	setting.LoadAllowEmpty()
 | 
						setting.InitProviderAllowEmpty()
 | 
				
			||||||
 | 
						setting.LoadCommonSettings()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setting.RepoRootPath, err = os.MkdirTemp(os.TempDir(), "repos")
 | 
						setting.RepoRootPath, err = os.MkdirTemp(os.TempDir(), "repos")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -82,7 +83,7 @@ func runPR() {
 | 
				
			|||||||
		setting.Database.Path = ":memory:"
 | 
							setting.Database.Path = ":memory:"
 | 
				
			||||||
		setting.Database.Timeout = 500
 | 
							setting.Database.Timeout = 500
 | 
				
			||||||
	*/
 | 
						*/
 | 
				
			||||||
	dbCfg := setting.Cfg.Section("database")
 | 
						dbCfg := setting.CfgProvider.Section("database")
 | 
				
			||||||
	dbCfg.NewKey("DB_TYPE", "sqlite3")
 | 
						dbCfg.NewKey("DB_TYPE", "sqlite3")
 | 
				
			||||||
	dbCfg.NewKey("PATH", ":memory:")
 | 
						dbCfg.NewKey("PATH", ":memory:")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,7 +13,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
	setting.SetCustomPathAndConf("", "", "")
 | 
						setting.SetCustomPathAndConf("", "", "")
 | 
				
			||||||
	setting.LoadForTest()
 | 
						setting.InitProviderAndLoadCommonSettingsForTest()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestMain(m *testing.M) {
 | 
					func TestMain(m *testing.M) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,7 +13,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
	setting.SetCustomPathAndConf("", "", "")
 | 
						setting.SetCustomPathAndConf("", "", "")
 | 
				
			||||||
	setting.LoadForTest()
 | 
						setting.InitProviderAndLoadCommonSettingsForTest()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestMain(m *testing.M) {
 | 
					func TestMain(m *testing.M) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
	setting.SetCustomPathAndConf("", "", "")
 | 
						setting.SetCustomPathAndConf("", "", "")
 | 
				
			||||||
	setting.LoadForTest()
 | 
						setting.InitProviderAndLoadCommonSettingsForTest()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestFixturesAreConsistent(t *testing.T) {
 | 
					func TestFixturesAreConsistent(t *testing.T) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
	setting.SetCustomPathAndConf("", "", "")
 | 
						setting.SetCustomPathAndConf("", "", "")
 | 
				
			||||||
	setting.LoadForTest()
 | 
						setting.InitProviderAndLoadCommonSettingsForTest()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TestFixturesAreConsistent assert that test fixtures are consistent
 | 
					// TestFixturesAreConsistent assert that test fixtures are consistent
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -149,13 +149,13 @@ func MainTest(m *testing.M) {
 | 
				
			|||||||
	setting.AppDataPath = tmpDataPath
 | 
						setting.AppDataPath = tmpDataPath
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setting.SetCustomPathAndConf("", "", "")
 | 
						setting.SetCustomPathAndConf("", "", "")
 | 
				
			||||||
	setting.LoadForTest()
 | 
						setting.InitProviderAndLoadCommonSettingsForTest()
 | 
				
			||||||
	if err = git.InitFull(context.Background()); err != nil {
 | 
						if err = git.InitFull(context.Background()); err != nil {
 | 
				
			||||||
		fmt.Printf("Unable to InitFull: %v\n", err)
 | 
							fmt.Printf("Unable to InitFull: %v\n", err)
 | 
				
			||||||
		os.Exit(1)
 | 
							os.Exit(1)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	setting.InitDBConfig()
 | 
						setting.LoadDBSetting()
 | 
				
			||||||
	setting.NewLogServices(true)
 | 
						setting.InitLogs(true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	exitStatus := m.Run()
 | 
						exitStatus := m.Run()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,7 +27,7 @@ var signedUserNameStringPointerKey interface{} = "signedUserNameStringPointerKey
 | 
				
			|||||||
// AccessLogger returns a middleware to log access logger
 | 
					// AccessLogger returns a middleware to log access logger
 | 
				
			||||||
func AccessLogger() func(http.Handler) http.Handler {
 | 
					func AccessLogger() func(http.Handler) http.Handler {
 | 
				
			||||||
	logger := log.GetLogger("access")
 | 
						logger := log.GetLogger("access")
 | 
				
			||||||
	logTemplate, _ := template.New("log").Parse(setting.AccessLogTemplate)
 | 
						logTemplate, _ := template.New("log").Parse(setting.Log.AccessLogTemplate)
 | 
				
			||||||
	return func(next http.Handler) http.Handler {
 | 
						return func(next http.Handler) http.Handler {
 | 
				
			||||||
		return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
 | 
							return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
 | 
				
			||||||
			start := time.Now()
 | 
								start := time.Now()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,10 +44,10 @@ func (w *wrappedLevelLogger) Log(skip int, level log.Level, format string, v ...
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func initDBDisableConsole(ctx context.Context, disableConsole bool) error {
 | 
					func initDBDisableConsole(ctx context.Context, disableConsole bool) error {
 | 
				
			||||||
	setting.LoadFromExisting()
 | 
						setting.InitProviderFromExistingFile()
 | 
				
			||||||
	setting.InitDBConfig()
 | 
						setting.LoadCommonSettings()
 | 
				
			||||||
 | 
						setting.LoadDBSetting()
 | 
				
			||||||
	setting.NewXORMLogService(disableConsole)
 | 
						setting.InitSQLLog(disableConsole)
 | 
				
			||||||
	if err := db.InitEngine(ctx); err != nil {
 | 
						if err := db.InitEngine(ctx); err != nil {
 | 
				
			||||||
		return fmt.Errorf("db.InitEngine: %w", err)
 | 
							return fmt.Errorf("db.InitEngine: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -71,7 +71,7 @@ func RunChecks(ctx context.Context, logger log.Logger, autofix bool, checks []*C
 | 
				
			|||||||
	for i, check := range checks {
 | 
						for i, check := range checks {
 | 
				
			||||||
		if !dbIsInit && !check.SkipDatabaseInitialization {
 | 
							if !dbIsInit && !check.SkipDatabaseInitialization {
 | 
				
			||||||
			// Only open database after the most basic configuration check
 | 
								// Only open database after the most basic configuration check
 | 
				
			||||||
			setting.EnableXORMLog = false
 | 
								setting.Log.EnableXORMLog = false
 | 
				
			||||||
			if err := initDBDisableConsole(ctx, true); err != nil {
 | 
								if err := initDBDisableConsole(ctx, true); err != nil {
 | 
				
			||||||
				logger.Error("Error whilst initializing the database: %v", err)
 | 
									logger.Error("Error whilst initializing the database: %v", err)
 | 
				
			||||||
				logger.Error("Check if you are using the right config file. You can use a --config directive to specify one.")
 | 
									logger.Error("Check if you are using the right config file. You can use a --config directive to specify one.")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -67,7 +67,8 @@ func checkConfigurationFiles(ctx context.Context, logger log.Logger, autofix boo
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setting.LoadFromExisting()
 | 
						setting.InitProviderFromExistingFile()
 | 
				
			||||||
 | 
						setting.LoadCommonSettings()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	configurationFiles := []configurationFile{
 | 
						configurationFiles := []configurationFile{
 | 
				
			||||||
		{"Configuration File Path", setting.CustomConf, false, true, false},
 | 
							{"Configuration File Path", setting.CustomConf, false, true, false},
 | 
				
			||||||
@@ -75,7 +76,7 @@ func checkConfigurationFiles(ctx context.Context, logger log.Logger, autofix boo
 | 
				
			|||||||
		{"Data Root Path", setting.AppDataPath, true, true, true},
 | 
							{"Data Root Path", setting.AppDataPath, true, true, true},
 | 
				
			||||||
		{"Custom File Root Path", setting.CustomPath, true, false, false},
 | 
							{"Custom File Root Path", setting.CustomPath, true, false, false},
 | 
				
			||||||
		{"Work directory", setting.AppWorkPath, true, true, false},
 | 
							{"Work directory", setting.AppWorkPath, true, true, false},
 | 
				
			||||||
		{"Log Root Path", setting.LogRootPath, true, true, true},
 | 
							{"Log Root Path", setting.Log.RootPath, true, true, true},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if options.IsDynamic() {
 | 
						if options.IsDynamic() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,12 +41,8 @@ var (
 | 
				
			|||||||
// NewContext loads custom highlight map from local config
 | 
					// NewContext loads custom highlight map from local config
 | 
				
			||||||
func NewContext() {
 | 
					func NewContext() {
 | 
				
			||||||
	once.Do(func() {
 | 
						once.Do(func() {
 | 
				
			||||||
		if setting.Cfg != nil {
 | 
							highlightMapping = setting.GetHighlightMapping()
 | 
				
			||||||
			keys := setting.Cfg.Section("highlight.mapping").Keys()
 | 
					
 | 
				
			||||||
			for i := range keys {
 | 
					 | 
				
			||||||
				highlightMapping[keys[i].Name()] = keys[i].Value()
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		// The size 512 is simply a conservative rule of thumb
 | 
							// The size 512 is simply a conservative rule of thumb
 | 
				
			||||||
		c, err := lru.New2Q(512)
 | 
							c, err := lru.New2Q(512)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,11 +27,11 @@ func TestMain(m *testing.M) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func TestBleveSearchIssues(t *testing.T) {
 | 
					func TestBleveSearchIssues(t *testing.T) {
 | 
				
			||||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
						assert.NoError(t, unittest.PrepareTestDatabase())
 | 
				
			||||||
	setting.Cfg = ini.Empty()
 | 
						setting.CfgProvider = ini.Empty()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tmpIndexerDir := t.TempDir()
 | 
						tmpIndexerDir := t.TempDir()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setting.Cfg.Section("queue.issue_indexer").Key("DATADIR").MustString(path.Join(tmpIndexerDir, "issues.queue"))
 | 
						setting.CfgProvider.Section("queue.issue_indexer").Key("DATADIR").MustString(path.Join(tmpIndexerDir, "issues.queue"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	oldIssuePath := setting.Indexer.IssuePath
 | 
						oldIssuePath := setting.Indexer.IssuePath
 | 
				
			||||||
	setting.Indexer.IssuePath = path.Join(tmpIndexerDir, "issues.queue")
 | 
						setting.Indexer.IssuePath = path.Join(tmpIndexerDir, "issues.queue")
 | 
				
			||||||
@@ -40,7 +40,7 @@ func TestBleveSearchIssues(t *testing.T) {
 | 
				
			|||||||
	}()
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setting.Indexer.IssueType = "bleve"
 | 
						setting.Indexer.IssueType = "bleve"
 | 
				
			||||||
	setting.NewQueueService()
 | 
						setting.LoadQueueSettings()
 | 
				
			||||||
	InitIssueIndexer(true)
 | 
						InitIssueIndexer(true)
 | 
				
			||||||
	defer func() {
 | 
						defer func() {
 | 
				
			||||||
		indexer := holder.get()
 | 
							indexer := holder.get()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,9 +29,9 @@ func TestMain(m *testing.M) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func TestRepoStatsIndex(t *testing.T) {
 | 
					func TestRepoStatsIndex(t *testing.T) {
 | 
				
			||||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
						assert.NoError(t, unittest.PrepareTestDatabase())
 | 
				
			||||||
	setting.Cfg = ini.Empty()
 | 
						setting.CfgProvider = ini.Empty()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setting.NewQueueService()
 | 
						setting.LoadQueueSettings()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err := Init()
 | 
						err := Init()
 | 
				
			||||||
	assert.NoError(t, err)
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,7 +28,8 @@ var localMetas = map[string]string{
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestMain(m *testing.M) {
 | 
					func TestMain(m *testing.M) {
 | 
				
			||||||
	setting.LoadAllowEmpty()
 | 
						setting.InitProviderAllowEmpty()
 | 
				
			||||||
 | 
						setting.LoadCommonSettings()
 | 
				
			||||||
	if err := git.InitSimple(context.Background()); err != nil {
 | 
						if err := git.InitSimple(context.Background()); err != nil {
 | 
				
			||||||
		log.Fatal("git init failed, err: %v", err)
 | 
							log.Fatal("git init failed, err: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,7 +33,8 @@ var localMetas = map[string]string{
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestMain(m *testing.M) {
 | 
					func TestMain(m *testing.M) {
 | 
				
			||||||
	setting.LoadAllowEmpty()
 | 
						setting.InitProviderAllowEmpty()
 | 
				
			||||||
 | 
						setting.LoadCommonSettings()
 | 
				
			||||||
	if err := git.InitSimple(context.Background()); err != nil {
 | 
						if err := git.InitSimple(context.Background()); err != nil {
 | 
				
			||||||
		log.Fatal("git init failed, err: %v", err)
 | 
							log.Fatal("git init failed, err: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,11 +19,11 @@ var (
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newActions() {
 | 
					func loadActionsFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	sec := Cfg.Section("actions")
 | 
						sec := rootCfg.Section("actions")
 | 
				
			||||||
	if err := sec.MapTo(&Actions); err != nil {
 | 
						if err := sec.MapTo(&Actions); err != nil {
 | 
				
			||||||
		log.Fatal("Failed to map Actions settings: %v", err)
 | 
							log.Fatal("Failed to map Actions settings: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Actions.Storage = getStorage("actions_log", "", nil)
 | 
						Actions.Storage = getStorage(rootCfg, "actions_log", "", nil)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										16
									
								
								modules/setting/admin.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								modules/setting/admin.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					// Copyright 2023 The Gitea Authors. All rights reserved.
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: MIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package setting
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Admin settings
 | 
				
			||||||
 | 
					var Admin struct {
 | 
				
			||||||
 | 
						DisableRegularOrgCreation bool
 | 
				
			||||||
 | 
						DefaultEmailNotification  string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func loadAdminFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
 | 
						mustMapSetting(rootCfg, "admin", &Admin)
 | 
				
			||||||
 | 
						sec := rootCfg.Section("admin")
 | 
				
			||||||
 | 
						Admin.DefaultEmailNotification = sec.Key("DEFAULT_EMAIL_NOTIFICATIONS").MustString("enabled")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										40
									
								
								modules/setting/api.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								modules/setting/api.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					// Copyright 2023 The Gitea Authors. All rights reserved.
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: MIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package setting
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
 | 
						"path"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// API settings
 | 
				
			||||||
 | 
					var API = struct {
 | 
				
			||||||
 | 
						EnableSwagger          bool
 | 
				
			||||||
 | 
						SwaggerURL             string
 | 
				
			||||||
 | 
						MaxResponseItems       int
 | 
				
			||||||
 | 
						DefaultPagingNum       int
 | 
				
			||||||
 | 
						DefaultGitTreesPerPage int
 | 
				
			||||||
 | 
						DefaultMaxBlobSize     int64
 | 
				
			||||||
 | 
					}{
 | 
				
			||||||
 | 
						EnableSwagger:          true,
 | 
				
			||||||
 | 
						SwaggerURL:             "",
 | 
				
			||||||
 | 
						MaxResponseItems:       50,
 | 
				
			||||||
 | 
						DefaultPagingNum:       30,
 | 
				
			||||||
 | 
						DefaultGitTreesPerPage: 1000,
 | 
				
			||||||
 | 
						DefaultMaxBlobSize:     10485760,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func loadAPIFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
 | 
						mustMapSetting(rootCfg, "api", &API)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						defaultAppURL := string(Protocol) + "://" + Domain + ":" + HTTPPort
 | 
				
			||||||
 | 
						u, err := url.Parse(rootCfg.Section("server").Key("ROOT_URL").MustString(defaultAppURL))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Fatal("Invalid ROOT_URL '%s': %s", AppURL, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						u.Path = path.Join(u.Path, "api", "swagger")
 | 
				
			||||||
 | 
						API.SwaggerURL = u.String()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -20,11 +20,11 @@ var Attachment = struct {
 | 
				
			|||||||
	Enabled:      true,
 | 
						Enabled:      true,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newAttachmentService() {
 | 
					func loadAttachmentFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	sec := Cfg.Section("attachment")
 | 
						sec := rootCfg.Section("attachment")
 | 
				
			||||||
	storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
						storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Attachment.Storage = getStorage("attachments", storageType, sec)
 | 
						Attachment.Storage = getStorage(rootCfg, "attachments", storageType, sec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Attachment.AllowedTypes = sec.Key("ALLOWED_TYPES").MustString(".csv,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.xls,.xlsx,.zip")
 | 
						Attachment.AllowedTypes = sec.Key("ALLOWED_TYPES").MustString(".csv,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.xls,.xlsx,.zip")
 | 
				
			||||||
	Attachment.MaxSize = sec.Key("MAX_SIZE").MustInt64(4)
 | 
						Attachment.MaxSize = sec.Key("MAX_SIZE").MustInt64(4)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -49,8 +49,8 @@ var CacheService = struct {
 | 
				
			|||||||
// MemcacheMaxTTL represents the maximum memcache TTL
 | 
					// MemcacheMaxTTL represents the maximum memcache TTL
 | 
				
			||||||
const MemcacheMaxTTL = 30 * 24 * time.Hour
 | 
					const MemcacheMaxTTL = 30 * 24 * time.Hour
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newCacheService() {
 | 
					func loadCacheFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	sec := Cfg.Section("cache")
 | 
						sec := rootCfg.Section("cache")
 | 
				
			||||||
	if err := sec.MapTo(&CacheService); err != nil {
 | 
						if err := sec.MapTo(&CacheService); err != nil {
 | 
				
			||||||
		log.Fatal("Failed to map Cache settings: %v", err)
 | 
							log.Fatal("Failed to map Cache settings: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -79,7 +79,7 @@ func newCacheService() {
 | 
				
			|||||||
		Service.EnableCaptcha = false
 | 
							Service.EnableCaptcha = false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sec = Cfg.Section("cache.last_commit")
 | 
						sec = rootCfg.Section("cache.last_commit")
 | 
				
			||||||
	if !CacheService.Enabled {
 | 
						if !CacheService.Enabled {
 | 
				
			||||||
		CacheService.LastCommit.Enabled = false
 | 
							CacheService.LastCommit.Enabled = false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										22
									
								
								modules/setting/camo.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								modules/setting/camo.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					// Copyright 2023 The Gitea Authors. All rights reserved.
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: MIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package setting
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "code.gitea.io/gitea/modules/log"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var Camo = struct {
 | 
				
			||||||
 | 
						Enabled   bool
 | 
				
			||||||
 | 
						ServerURL string `ini:"SERVER_URL"`
 | 
				
			||||||
 | 
						HMACKey   string `ini:"HMAC_KEY"`
 | 
				
			||||||
 | 
						Allways   bool
 | 
				
			||||||
 | 
					}{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func loadCamoFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
 | 
						mustMapSetting(rootCfg, "camo", &Camo)
 | 
				
			||||||
 | 
						if Camo.Enabled {
 | 
				
			||||||
 | 
							if Camo.ServerURL == "" || Camo.HMACKey == "" {
 | 
				
			||||||
 | 
								log.Fatal(`Camo settings require "SERVER_URL" and HMAC_KEY`)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										39
									
								
								modules/setting/config_provider.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								modules/setting/config_provider.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					// Copyright 2023 The Gitea Authors. All rights reserved.
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: MIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package setting
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ini "gopkg.in/ini.v1"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ConfigProvider represents a config provider
 | 
				
			||||||
 | 
					type ConfigProvider interface {
 | 
				
			||||||
 | 
						Section(section string) *ini.Section
 | 
				
			||||||
 | 
						NewSection(name string) (*ini.Section, error)
 | 
				
			||||||
 | 
						GetSection(name string) (*ini.Section, error)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// a file is an implementation ConfigProvider and other implementations are possible, i.e. from docker, k8s, …
 | 
				
			||||||
 | 
					var _ ConfigProvider = &ini.File{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func mustMapSetting(rootCfg ConfigProvider, sectionName string, setting interface{}) {
 | 
				
			||||||
 | 
						if err := rootCfg.Section(sectionName).MapTo(setting); err != nil {
 | 
				
			||||||
 | 
							log.Fatal("Failed to map %s settings: %v", sectionName, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func deprecatedSetting(rootCfg ConfigProvider, oldSection, oldKey, newSection, newKey string) {
 | 
				
			||||||
 | 
						if rootCfg.Section(oldSection).HasKey(oldKey) {
 | 
				
			||||||
 | 
							log.Error("Deprecated fallback `[%s]` `%s` present. Use `[%s]` `%s` instead. This fallback will be removed in v1.19.0", oldSection, oldKey, newSection, newKey)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// deprecatedSettingDB add a hint that the configuration has been moved to database but still kept in app.ini
 | 
				
			||||||
 | 
					func deprecatedSettingDB(rootCfg ConfigProvider, oldSection, oldKey string) {
 | 
				
			||||||
 | 
						if rootCfg.Section(oldSection).HasKey(oldKey) {
 | 
				
			||||||
 | 
							log.Error("Deprecated `[%s]` `%s` present which has been copied to database table sys_setting", oldSection, oldKey)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -27,12 +27,8 @@ var CORSConfig = struct {
 | 
				
			|||||||
	XFrameOptions: "SAMEORIGIN",
 | 
						XFrameOptions: "SAMEORIGIN",
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newCORSService() {
 | 
					func loadCorsFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	sec := Cfg.Section("cors")
 | 
						mustMapSetting(rootCfg, "cors", &CORSConfig)
 | 
				
			||||||
	if err := sec.MapTo(&CORSConfig); err != nil {
 | 
					 | 
				
			||||||
		log.Fatal("Failed to map cors settings: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if CORSConfig.Enabled {
 | 
						if CORSConfig.Enabled {
 | 
				
			||||||
		log.Info("CORS Service Enabled")
 | 
							log.Info("CORS Service Enabled")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,11 @@ import "reflect"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// GetCronSettings maps the cron subsection to the provided config
 | 
					// GetCronSettings maps the cron subsection to the provided config
 | 
				
			||||||
func GetCronSettings(name string, config interface{}) (interface{}, error) {
 | 
					func GetCronSettings(name string, config interface{}) (interface{}, error) {
 | 
				
			||||||
	if err := Cfg.Section("cron." + name).MapTo(config); err != nil {
 | 
						return getCronSettings(CfgProvider, name, config)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getCronSettings(rootCfg ConfigProvider, name string, config interface{}) (interface{}, error) {
 | 
				
			||||||
 | 
						if err := rootCfg.Section("cron." + name).MapTo(config); err != nil {
 | 
				
			||||||
		return config, err
 | 
							return config, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -18,7 +22,7 @@ func GetCronSettings(name string, config interface{}) (interface{}, error) {
 | 
				
			|||||||
		field := val.Field(i)
 | 
							field := val.Field(i)
 | 
				
			||||||
		tpField := typ.Field(i)
 | 
							tpField := typ.Field(i)
 | 
				
			||||||
		if tpField.Type.Kind() == reflect.Struct && tpField.Anonymous {
 | 
							if tpField.Type.Kind() == reflect.Struct && tpField.Anonymous {
 | 
				
			||||||
			if err := Cfg.Section("cron." + name).MapTo(field.Addr().Interface()); err != nil {
 | 
								if err := rootCfg.Section("cron." + name).MapTo(field.Addr().Interface()); err != nil {
 | 
				
			||||||
				return config, err
 | 
									return config, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,7 @@ import (
 | 
				
			|||||||
	ini "gopkg.in/ini.v1"
 | 
						ini "gopkg.in/ini.v1"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Test_GetCronSettings(t *testing.T) {
 | 
					func Test_getCronSettings(t *testing.T) {
 | 
				
			||||||
	type BaseStruct struct {
 | 
						type BaseStruct struct {
 | 
				
			||||||
		Base   bool
 | 
							Base   bool
 | 
				
			||||||
		Second string
 | 
							Second string
 | 
				
			||||||
@@ -27,7 +27,8 @@ Base = true
 | 
				
			|||||||
Second = white rabbit
 | 
					Second = white rabbit
 | 
				
			||||||
Extend = true
 | 
					Extend = true
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
	Cfg, _ = ini.Load([]byte(iniStr))
 | 
						cfg, err := ini.Load([]byte(iniStr))
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	extended := &Extended{
 | 
						extended := &Extended{
 | 
				
			||||||
		BaseStruct: BaseStruct{
 | 
							BaseStruct: BaseStruct{
 | 
				
			||||||
@@ -35,8 +36,7 @@ Extend = true
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_, err := GetCronSettings("test", extended)
 | 
						_, err = getCronSettings(cfg, "test", extended)
 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert.NoError(t, err)
 | 
						assert.NoError(t, err)
 | 
				
			||||||
	assert.True(t, extended.Base)
 | 
						assert.True(t, extended.Base)
 | 
				
			||||||
	assert.EqualValues(t, extended.Second, "white rabbit")
 | 
						assert.EqualValues(t, extended.Second, "white rabbit")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,9 +56,9 @@ var (
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// InitDBConfig loads the database settings
 | 
					// LoadDBSetting loads the database settings
 | 
				
			||||||
func InitDBConfig() {
 | 
					func LoadDBSetting() {
 | 
				
			||||||
	sec := Cfg.Section("database")
 | 
						sec := CfgProvider.Section("database")
 | 
				
			||||||
	Database.Type = sec.Key("DB_TYPE").String()
 | 
						Database.Type = sec.Key("DB_TYPE").String()
 | 
				
			||||||
	defaultCharset := "utf8"
 | 
						defaultCharset := "utf8"
 | 
				
			||||||
	Database.UseMySQL = false
 | 
						Database.UseMySQL = false
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,39 +0,0 @@
 | 
				
			|||||||
// Copyright 2021 The Gitea Authors. All rights reserved.
 | 
					 | 
				
			||||||
// SPDX-License-Identifier: MIT
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package setting
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"os"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// PrepareAppDataPath creates app data directory if necessary
 | 
					 | 
				
			||||||
func PrepareAppDataPath() error {
 | 
					 | 
				
			||||||
	// FIXME: There are too many calls to MkdirAll in old code. It is incorrect.
 | 
					 | 
				
			||||||
	// For example, if someDir=/mnt/vol1/gitea-home/data, if the mount point /mnt/vol1 is not mounted when Gitea runs,
 | 
					 | 
				
			||||||
	// then gitea will make new empty directories in /mnt/vol1, all are stored in the root filesystem.
 | 
					 | 
				
			||||||
	// The correct behavior should be: creating parent directories is end users' duty. We only create sub-directories in existing parent directories.
 | 
					 | 
				
			||||||
	// For quickstart, the parent directories should be created automatically for first startup (eg: a flag or a check of INSTALL_LOCK).
 | 
					 | 
				
			||||||
	// Now we can take the first step to do correctly (using Mkdir) in other packages, and prepare the AppDataPath here, then make a refactor in future.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	st, err := os.Stat(AppDataPath)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if os.IsNotExist(err) {
 | 
					 | 
				
			||||||
		err = os.MkdirAll(AppDataPath, os.ModePerm)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return fmt.Errorf("unable to create the APP_DATA_PATH directory: %q, Error: %w", AppDataPath, err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("unable to use APP_DATA_PATH %q. Error: %w", AppDataPath, err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !st.IsDir() /* also works for symlink */ {
 | 
					 | 
				
			||||||
		return fmt.Errorf("the APP_DATA_PATH %q is not a directory (or symlink to a directory) and can't be used", AppDataPath)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -33,8 +33,8 @@ var (
 | 
				
			|||||||
// HttpsigAlgs is a constant slice of httpsig algorithm objects
 | 
					// HttpsigAlgs is a constant slice of httpsig algorithm objects
 | 
				
			||||||
var HttpsigAlgs []httpsig.Algorithm
 | 
					var HttpsigAlgs []httpsig.Algorithm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newFederationService() {
 | 
					func loadFederationFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	if err := Cfg.Section("federation").MapTo(&Federation); err != nil {
 | 
						if err := rootCfg.Section("federation").MapTo(&Federation); err != nil {
 | 
				
			||||||
		log.Fatal("Failed to map Federation settings: %v", err)
 | 
							log.Fatal("Failed to map Federation settings: %v", err)
 | 
				
			||||||
	} else if !httpsig.IsSupportedDigestAlgorithm(Federation.DigestAlgorithm) {
 | 
						} else if !httpsig.IsSupportedDigestAlgorithm(Federation.DigestAlgorithm) {
 | 
				
			||||||
		log.Fatal("unsupported digest algorithm: %s", Federation.DigestAlgorithm)
 | 
							log.Fatal("unsupported digest algorithm: %s", Federation.DigestAlgorithm)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -67,9 +67,8 @@ var Git = struct {
 | 
				
			|||||||
	},
 | 
						},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newGit() {
 | 
					func loadGitFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	sec := Cfg.Section("git")
 | 
						sec := rootCfg.Section("git")
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err := sec.MapTo(&Git); err != nil {
 | 
						if err := sec.MapTo(&Git); err != nil {
 | 
				
			||||||
		log.Fatal("Failed to map Git settings: %v", err)
 | 
							log.Fatal("Failed to map Git settings: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										17
									
								
								modules/setting/highlight.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								modules/setting/highlight.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					// Copyright 2023 The Gitea Authors. All rights reserved.
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: MIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package setting
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func GetHighlightMapping() map[string]string {
 | 
				
			||||||
 | 
						highlightMapping := map[string]string{}
 | 
				
			||||||
 | 
						if CfgProvider == nil {
 | 
				
			||||||
 | 
							return highlightMapping
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						keys := CfgProvider.Section("highlight.mapping").Keys()
 | 
				
			||||||
 | 
						for _, key := range keys {
 | 
				
			||||||
 | 
							highlightMapping[key.Name()] = key.Value()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return highlightMapping
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -47,3 +47,20 @@ func defaultI18nNames() (res []string) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return res
 | 
						return res
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						// I18n settings
 | 
				
			||||||
 | 
						Langs []string
 | 
				
			||||||
 | 
						Names []string
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func loadI18nFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
 | 
						Langs = rootCfg.Section("i18n").Key("LANGS").Strings(",")
 | 
				
			||||||
 | 
						if len(Langs) == 0 {
 | 
				
			||||||
 | 
							Langs = defaultI18nLangs()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						Names = rootCfg.Section("i18n").Key("NAMES").Strings(",")
 | 
				
			||||||
 | 
						if len(Names) == 0 {
 | 
				
			||||||
 | 
							Names = defaultI18nNames()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,10 +31,8 @@ var IncomingEmail = struct {
 | 
				
			|||||||
	MaximumMessageSize:   10485760,
 | 
						MaximumMessageSize:   10485760,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newIncomingEmail() {
 | 
					func loadIncomingEmailFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	if err := Cfg.Section("email.incoming").MapTo(&IncomingEmail); err != nil {
 | 
						mustMapSetting(rootCfg, "email.incoming", &IncomingEmail)
 | 
				
			||||||
		log.Fatal("Unable to map [email.incoming] section on to IncomingEmail. Error: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if !IncomingEmail.Enabled {
 | 
						if !IncomingEmail.Enabled {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,8 +45,8 @@ var Indexer = struct {
 | 
				
			|||||||
	ExcludeVendored:    true,
 | 
						ExcludeVendored:    true,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newIndexerService() {
 | 
					func loadIndexerFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	sec := Cfg.Section("indexer")
 | 
						sec := rootCfg.Section("indexer")
 | 
				
			||||||
	Indexer.IssueType = sec.Key("ISSUE_INDEXER_TYPE").MustString("bleve")
 | 
						Indexer.IssueType = sec.Key("ISSUE_INDEXER_TYPE").MustString("bleve")
 | 
				
			||||||
	Indexer.IssuePath = filepath.ToSlash(sec.Key("ISSUE_INDEXER_PATH").MustString(filepath.ToSlash(filepath.Join(AppDataPath, "indexers/issues.bleve"))))
 | 
						Indexer.IssuePath = filepath.ToSlash(sec.Key("ISSUE_INDEXER_PATH").MustString(filepath.ToSlash(filepath.Join(AppDataPath, "indexers/issues.bleve"))))
 | 
				
			||||||
	if !filepath.IsAbs(Indexer.IssuePath) {
 | 
						if !filepath.IsAbs(Indexer.IssuePath) {
 | 
				
			||||||
@@ -57,11 +57,11 @@ func newIndexerService() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// The following settings are deprecated and can be overridden by settings in [queue] or [queue.issue_indexer]
 | 
						// The following settings are deprecated and can be overridden by settings in [queue] or [queue.issue_indexer]
 | 
				
			||||||
	// FIXME: DEPRECATED to be removed in v1.18.0
 | 
						// FIXME: DEPRECATED to be removed in v1.18.0
 | 
				
			||||||
	deprecatedSetting("indexer", "ISSUE_INDEXER_QUEUE_TYPE", "queue.issue_indexer", "TYPE")
 | 
						deprecatedSetting(rootCfg, "indexer", "ISSUE_INDEXER_QUEUE_TYPE", "queue.issue_indexer", "TYPE")
 | 
				
			||||||
	deprecatedSetting("indexer", "ISSUE_INDEXER_QUEUE_DIR", "queue.issue_indexer", "DATADIR")
 | 
						deprecatedSetting(rootCfg, "indexer", "ISSUE_INDEXER_QUEUE_DIR", "queue.issue_indexer", "DATADIR")
 | 
				
			||||||
	deprecatedSetting("indexer", "ISSUE_INDEXER_QUEUE_CONN_STR", "queue.issue_indexer", "CONN_STR")
 | 
						deprecatedSetting(rootCfg, "indexer", "ISSUE_INDEXER_QUEUE_CONN_STR", "queue.issue_indexer", "CONN_STR")
 | 
				
			||||||
	deprecatedSetting("indexer", "ISSUE_INDEXER_QUEUE_BATCH_NUMBER", "queue.issue_indexer", "BATCH_LENGTH")
 | 
						deprecatedSetting(rootCfg, "indexer", "ISSUE_INDEXER_QUEUE_BATCH_NUMBER", "queue.issue_indexer", "BATCH_LENGTH")
 | 
				
			||||||
	deprecatedSetting("indexer", "UPDATE_BUFFER_LEN", "queue.issue_indexer", "LENGTH")
 | 
						deprecatedSetting(rootCfg, "indexer", "UPDATE_BUFFER_LEN", "queue.issue_indexer", "LENGTH")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Indexer.RepoIndexerEnabled = sec.Key("REPO_INDEXER_ENABLED").MustBool(false)
 | 
						Indexer.RepoIndexerEnabled = sec.Key("REPO_INDEXER_ENABLED").MustBool(false)
 | 
				
			||||||
	Indexer.RepoType = sec.Key("REPO_INDEXER_TYPE").MustString("bleve")
 | 
						Indexer.RepoType = sec.Key("REPO_INDEXER_TYPE").MustString("bleve")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,22 +25,22 @@ var LFS = struct {
 | 
				
			|||||||
	Storage
 | 
						Storage
 | 
				
			||||||
}{}
 | 
					}{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newLFSService() {
 | 
					func loadLFSFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	sec := Cfg.Section("server")
 | 
						sec := rootCfg.Section("server")
 | 
				
			||||||
	if err := sec.MapTo(&LFS); err != nil {
 | 
						if err := sec.MapTo(&LFS); err != nil {
 | 
				
			||||||
		log.Fatal("Failed to map LFS settings: %v", err)
 | 
							log.Fatal("Failed to map LFS settings: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	lfsSec := Cfg.Section("lfs")
 | 
						lfsSec := rootCfg.Section("lfs")
 | 
				
			||||||
	storageType := lfsSec.Key("STORAGE_TYPE").MustString("")
 | 
						storageType := lfsSec.Key("STORAGE_TYPE").MustString("")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Specifically default PATH to LFS_CONTENT_PATH
 | 
						// Specifically default PATH to LFS_CONTENT_PATH
 | 
				
			||||||
	// FIXME: DEPRECATED to be removed in v1.18.0
 | 
						// FIXME: DEPRECATED to be removed in v1.18.0
 | 
				
			||||||
	deprecatedSetting("server", "LFS_CONTENT_PATH", "lfs", "PATH")
 | 
						deprecatedSetting(rootCfg, "server", "LFS_CONTENT_PATH", "lfs", "PATH")
 | 
				
			||||||
	lfsSec.Key("PATH").MustString(
 | 
						lfsSec.Key("PATH").MustString(
 | 
				
			||||||
		sec.Key("LFS_CONTENT_PATH").String())
 | 
							sec.Key("LFS_CONTENT_PATH").String())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LFS.Storage = getStorage("lfs", storageType, lfsSec)
 | 
						LFS.Storage = getStorage(rootCfg, "lfs", storageType, lfsSec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Rest of LFS service settings
 | 
						// Rest of LFS service settings
 | 
				
			||||||
	if LFS.LocksPagingNum == 0 {
 | 
						if LFS.LocksPagingNum == 0 {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,6 +25,21 @@ var (
 | 
				
			|||||||
	logDescriptions = make(map[string]*LogDescription)
 | 
						logDescriptions = make(map[string]*LogDescription)
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Log settings
 | 
				
			||||||
 | 
					var Log struct {
 | 
				
			||||||
 | 
						Level              log.Level
 | 
				
			||||||
 | 
						StacktraceLogLevel string
 | 
				
			||||||
 | 
						RootPath           string
 | 
				
			||||||
 | 
						EnableSSHLog       bool
 | 
				
			||||||
 | 
						EnableXORMLog      bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						DisableRouterLog bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EnableAccessLog   bool
 | 
				
			||||||
 | 
						AccessLogTemplate string
 | 
				
			||||||
 | 
						BufferLength      int64
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetLogDescriptions returns a race safe set of descriptions
 | 
					// GetLogDescriptions returns a race safe set of descriptions
 | 
				
			||||||
func GetLogDescriptions() map[string]*LogDescription {
 | 
					func GetLogDescriptions() map[string]*LogDescription {
 | 
				
			||||||
	descriptionLock.RLock()
 | 
						descriptionLock.RLock()
 | 
				
			||||||
@@ -94,9 +109,9 @@ type defaultLogOptions struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func newDefaultLogOptions() defaultLogOptions {
 | 
					func newDefaultLogOptions() defaultLogOptions {
 | 
				
			||||||
	return defaultLogOptions{
 | 
						return defaultLogOptions{
 | 
				
			||||||
		levelName:      LogLevel.String(),
 | 
							levelName:      Log.Level.String(),
 | 
				
			||||||
		flags:          "stdflags",
 | 
							flags:          "stdflags",
 | 
				
			||||||
		filename:       filepath.Join(LogRootPath, "gitea.log"),
 | 
							filename:       filepath.Join(Log.RootPath, "gitea.log"),
 | 
				
			||||||
		bufferLength:   10000,
 | 
							bufferLength:   10000,
 | 
				
			||||||
		disableConsole: false,
 | 
							disableConsole: false,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -125,10 +140,33 @@ func getStacktraceLogLevel(section *ini.Section, key, defaultValue string) strin
 | 
				
			|||||||
	return log.FromString(value).String()
 | 
						return log.FromString(value).String()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func loadLogFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
 | 
						sec := rootCfg.Section("log")
 | 
				
			||||||
 | 
						Log.Level = getLogLevel(sec, "LEVEL", log.INFO)
 | 
				
			||||||
 | 
						Log.StacktraceLogLevel = getStacktraceLogLevel(sec, "STACKTRACE_LEVEL", "None")
 | 
				
			||||||
 | 
						Log.RootPath = sec.Key("ROOT_PATH").MustString(path.Join(AppWorkPath, "log"))
 | 
				
			||||||
 | 
						forcePathSeparator(Log.RootPath)
 | 
				
			||||||
 | 
						Log.BufferLength = sec.Key("BUFFER_LEN").MustInt64(10000)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Log.EnableSSHLog = sec.Key("ENABLE_SSH_LOG").MustBool(false)
 | 
				
			||||||
 | 
						Log.EnableAccessLog = sec.Key("ENABLE_ACCESS_LOG").MustBool(false)
 | 
				
			||||||
 | 
						Log.AccessLogTemplate = sec.Key("ACCESS_LOG_TEMPLATE").MustString(
 | 
				
			||||||
 | 
							`{{.Ctx.RemoteAddr}} - {{.Identity}} {{.Start.Format "[02/Jan/2006:15:04:05 -0700]" }} "{{.Ctx.Req.Method}} {{.Ctx.Req.URL.RequestURI}} {{.Ctx.Req.Proto}}" {{.ResponseWriter.Status}} {{.ResponseWriter.Size}} "{{.Ctx.Req.Referer}}\" \"{{.Ctx.Req.UserAgent}}"`,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						// the `MustString` updates the default value, and `log.ACCESS` is used by `generateNamedLogger("access")` later
 | 
				
			||||||
 | 
						_ = rootCfg.Section("log").Key("ACCESS").MustString("file")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sec.Key("ROUTER").MustString("console")
 | 
				
			||||||
 | 
						// Allow [log]  DISABLE_ROUTER_LOG to override [server] DISABLE_ROUTER_LOG
 | 
				
			||||||
 | 
						Log.DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool(Log.DisableRouterLog)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Log.EnableXORMLog = rootCfg.Section("log").Key("ENABLE_XORM_LOG").MustBool(true)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func generateLogConfig(sec *ini.Section, name string, defaults defaultLogOptions) (mode, jsonConfig, levelName string) {
 | 
					func generateLogConfig(sec *ini.Section, name string, defaults defaultLogOptions) (mode, jsonConfig, levelName string) {
 | 
				
			||||||
	level := getLogLevel(sec, "LEVEL", LogLevel)
 | 
						level := getLogLevel(sec, "LEVEL", Log.Level)
 | 
				
			||||||
	levelName = level.String()
 | 
						levelName = level.String()
 | 
				
			||||||
	stacktraceLevelName := getStacktraceLogLevel(sec, "STACKTRACE_LEVEL", StacktraceLogLevel)
 | 
						stacktraceLevelName := getStacktraceLogLevel(sec, "STACKTRACE_LEVEL", Log.StacktraceLogLevel)
 | 
				
			||||||
	stacktraceLevel := log.FromString(stacktraceLevelName)
 | 
						stacktraceLevel := log.FromString(stacktraceLevelName)
 | 
				
			||||||
	mode = name
 | 
						mode = name
 | 
				
			||||||
	keys := sec.Keys()
 | 
						keys := sec.Keys()
 | 
				
			||||||
@@ -144,7 +182,7 @@ func generateLogConfig(sec *ini.Section, name string, defaults defaultLogOptions
 | 
				
			|||||||
			logPath = key.MustString(defaults.filename)
 | 
								logPath = key.MustString(defaults.filename)
 | 
				
			||||||
			forcePathSeparator(logPath)
 | 
								forcePathSeparator(logPath)
 | 
				
			||||||
			if !filepath.IsAbs(logPath) {
 | 
								if !filepath.IsAbs(logPath) {
 | 
				
			||||||
				logPath = path.Join(LogRootPath, logPath)
 | 
									logPath = path.Join(Log.RootPath, logPath)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		case "FLAGS":
 | 
							case "FLAGS":
 | 
				
			||||||
			flags = log.FlagsFromString(key.MustString(defaults.flags))
 | 
								flags = log.FlagsFromString(key.MustString(defaults.flags))
 | 
				
			||||||
@@ -213,12 +251,12 @@ func generateLogConfig(sec *ini.Section, name string, defaults defaultLogOptions
 | 
				
			|||||||
	return mode, jsonConfig, levelName
 | 
						return mode, jsonConfig, levelName
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func generateNamedLogger(key string, options defaultLogOptions) *LogDescription {
 | 
					func generateNamedLogger(rootCfg ConfigProvider, key string, options defaultLogOptions) *LogDescription {
 | 
				
			||||||
	description := LogDescription{
 | 
						description := LogDescription{
 | 
				
			||||||
		Name: key,
 | 
							Name: key,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sections := strings.Split(Cfg.Section("log").Key(strings.ToUpper(key)).MustString(""), ",")
 | 
						sections := strings.Split(rootCfg.Section("log").Key(strings.ToUpper(key)).MustString(""), ",")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for i := 0; i < len(sections); i++ {
 | 
						for i := 0; i < len(sections); i++ {
 | 
				
			||||||
		sections[i] = strings.TrimSpace(sections[i])
 | 
							sections[i] = strings.TrimSpace(sections[i])
 | 
				
			||||||
@@ -228,9 +266,9 @@ func generateNamedLogger(key string, options defaultLogOptions) *LogDescription
 | 
				
			|||||||
		if len(name) == 0 || (name == "console" && options.disableConsole) {
 | 
							if len(name) == 0 || (name == "console" && options.disableConsole) {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		sec, err := Cfg.GetSection("log." + name + "." + key)
 | 
							sec, err := rootCfg.GetSection("log." + name + "." + key)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			sec, _ = Cfg.NewSection("log." + name + "." + key)
 | 
								sec, _ = rootCfg.NewSection("log." + name + "." + key)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		provider, config, levelName := generateLogConfig(sec, name, options)
 | 
							provider, config, levelName := generateLogConfig(sec, name, options)
 | 
				
			||||||
@@ -253,46 +291,17 @@ func generateNamedLogger(key string, options defaultLogOptions) *LogDescription
 | 
				
			|||||||
	return &description
 | 
						return &description
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newAccessLogService() {
 | 
					// initLogFrom initializes logging with settings from configuration provider
 | 
				
			||||||
	EnableAccessLog = Cfg.Section("log").Key("ENABLE_ACCESS_LOG").MustBool(false)
 | 
					func initLogFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	AccessLogTemplate = Cfg.Section("log").Key("ACCESS_LOG_TEMPLATE").MustString(
 | 
						sec := rootCfg.Section("log")
 | 
				
			||||||
		`{{.Ctx.RemoteAddr}} - {{.Identity}} {{.Start.Format "[02/Jan/2006:15:04:05 -0700]" }} "{{.Ctx.Req.Method}} {{.Ctx.Req.URL.RequestURI}} {{.Ctx.Req.Proto}}" {{.ResponseWriter.Status}} {{.ResponseWriter.Size}} "{{.Ctx.Req.Referer}}\" \"{{.Ctx.Req.UserAgent}}"`,
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
	// the `MustString` updates the default value, and `log.ACCESS` is used by `generateNamedLogger("access")` later
 | 
					 | 
				
			||||||
	_ = Cfg.Section("log").Key("ACCESS").MustString("file")
 | 
					 | 
				
			||||||
	if EnableAccessLog {
 | 
					 | 
				
			||||||
		options := newDefaultLogOptions()
 | 
					 | 
				
			||||||
		options.filename = filepath.Join(LogRootPath, "access.log")
 | 
					 | 
				
			||||||
		options.flags = "" // For the router we don't want any prefixed flags
 | 
					 | 
				
			||||||
		options.bufferLength = Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000)
 | 
					 | 
				
			||||||
		generateNamedLogger("access", options)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func newRouterLogService() {
 | 
					 | 
				
			||||||
	Cfg.Section("log").Key("ROUTER").MustString("console")
 | 
					 | 
				
			||||||
	// Allow [log]  DISABLE_ROUTER_LOG to override [server] DISABLE_ROUTER_LOG
 | 
					 | 
				
			||||||
	DisableRouterLog = Cfg.Section("log").Key("DISABLE_ROUTER_LOG").MustBool(DisableRouterLog)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !DisableRouterLog {
 | 
					 | 
				
			||||||
		options := newDefaultLogOptions()
 | 
					 | 
				
			||||||
		options.filename = filepath.Join(LogRootPath, "router.log")
 | 
					 | 
				
			||||||
		options.flags = "date,time" // For the router we don't want any prefixed flags
 | 
					 | 
				
			||||||
		options.bufferLength = Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000)
 | 
					 | 
				
			||||||
		generateNamedLogger("router", options)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func newLogService() {
 | 
					 | 
				
			||||||
	options := newDefaultLogOptions()
 | 
						options := newDefaultLogOptions()
 | 
				
			||||||
	options.bufferLength = Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000)
 | 
						options.bufferLength = Log.BufferLength
 | 
				
			||||||
	EnableSSHLog = Cfg.Section("log").Key("ENABLE_SSH_LOG").MustBool(false)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	description := LogDescription{
 | 
						description := LogDescription{
 | 
				
			||||||
		Name: log.DEFAULT,
 | 
							Name: log.DEFAULT,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sections := strings.Split(Cfg.Section("log").Key("MODE").MustString("console"), ",")
 | 
						sections := strings.Split(sec.Key("MODE").MustString("console"), ",")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	useConsole := false
 | 
						useConsole := false
 | 
				
			||||||
	for _, name := range sections {
 | 
						for _, name := range sections {
 | 
				
			||||||
@@ -304,11 +313,11 @@ func newLogService() {
 | 
				
			|||||||
			useConsole = true
 | 
								useConsole = true
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		sec, err := Cfg.GetSection("log." + name + ".default")
 | 
							sec, err := rootCfg.GetSection("log." + name + ".default")
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			sec, err = Cfg.GetSection("log." + name)
 | 
								sec, err = rootCfg.GetSection("log." + name)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				sec, _ = Cfg.NewSection("log." + name)
 | 
									sec, _ = rootCfg.NewSection("log." + name)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -340,27 +349,45 @@ func newLogService() {
 | 
				
			|||||||
// RestartLogsWithPIDSuffix restarts the logs with a PID suffix on files
 | 
					// RestartLogsWithPIDSuffix restarts the logs with a PID suffix on files
 | 
				
			||||||
func RestartLogsWithPIDSuffix() {
 | 
					func RestartLogsWithPIDSuffix() {
 | 
				
			||||||
	filenameSuffix = fmt.Sprintf(".%d", os.Getpid())
 | 
						filenameSuffix = fmt.Sprintf(".%d", os.Getpid())
 | 
				
			||||||
	NewLogServices(false)
 | 
						InitLogs(false)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewLogServices creates all the log services
 | 
					// InitLogs creates all the log services
 | 
				
			||||||
func NewLogServices(disableConsole bool) {
 | 
					func InitLogs(disableConsole bool) {
 | 
				
			||||||
	newLogService()
 | 
						initLogFrom(CfgProvider)
 | 
				
			||||||
	newRouterLogService()
 | 
					 | 
				
			||||||
	newAccessLogService()
 | 
					 | 
				
			||||||
	NewXORMLogService(disableConsole)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewXORMLogService initializes xorm logger service
 | 
						if !Log.DisableRouterLog {
 | 
				
			||||||
func NewXORMLogService(disableConsole bool) {
 | 
					 | 
				
			||||||
	EnableXORMLog = Cfg.Section("log").Key("ENABLE_XORM_LOG").MustBool(true)
 | 
					 | 
				
			||||||
	if EnableXORMLog {
 | 
					 | 
				
			||||||
		options := newDefaultLogOptions()
 | 
							options := newDefaultLogOptions()
 | 
				
			||||||
		options.filename = filepath.Join(LogRootPath, "xorm.log")
 | 
							options.filename = filepath.Join(Log.RootPath, "router.log")
 | 
				
			||||||
		options.bufferLength = Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000)
 | 
							options.flags = "date,time" // For the router we don't want any prefixed flags
 | 
				
			||||||
 | 
							options.bufferLength = Log.BufferLength
 | 
				
			||||||
 | 
							generateNamedLogger(CfgProvider, "router", options)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if Log.EnableAccessLog {
 | 
				
			||||||
 | 
							options := newDefaultLogOptions()
 | 
				
			||||||
 | 
							options.filename = filepath.Join(Log.RootPath, "access.log")
 | 
				
			||||||
 | 
							options.flags = "" // For the router we don't want any prefixed flags
 | 
				
			||||||
 | 
							options.bufferLength = Log.BufferLength
 | 
				
			||||||
 | 
							generateNamedLogger(CfgProvider, "access", options)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						initSQLLogFrom(CfgProvider, disableConsole)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// InitSQLLog initializes xorm logger setting
 | 
				
			||||||
 | 
					func InitSQLLog(disableConsole bool) {
 | 
				
			||||||
 | 
						initSQLLogFrom(CfgProvider, disableConsole)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func initSQLLogFrom(rootCfg ConfigProvider, disableConsole bool) {
 | 
				
			||||||
 | 
						if Log.EnableXORMLog {
 | 
				
			||||||
 | 
							options := newDefaultLogOptions()
 | 
				
			||||||
 | 
							options.filename = filepath.Join(Log.RootPath, "xorm.log")
 | 
				
			||||||
 | 
							options.bufferLength = Log.BufferLength
 | 
				
			||||||
		options.disableConsole = disableConsole
 | 
							options.disableConsole = disableConsole
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Cfg.Section("log").Key("XORM").MustString(",")
 | 
							rootCfg.Section("log").Key("XORM").MustString(",")
 | 
				
			||||||
		generateNamedLogger("xorm", options)
 | 
							generateNamedLogger(rootCfg, "xorm", options)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,6 @@ import (
 | 
				
			|||||||
	"code.gitea.io/gitea/modules/log"
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	shellquote "github.com/kballard/go-shellquote"
 | 
						shellquote "github.com/kballard/go-shellquote"
 | 
				
			||||||
	ini "gopkg.in/ini.v1"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Mailer represents mail service.
 | 
					// Mailer represents mail service.
 | 
				
			||||||
@@ -50,7 +49,14 @@ type Mailer struct {
 | 
				
			|||||||
// MailService the global mailer
 | 
					// MailService the global mailer
 | 
				
			||||||
var MailService *Mailer
 | 
					var MailService *Mailer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func parseMailerConfig(rootCfg *ini.File) {
 | 
					func loadMailsFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
 | 
						loadMailerFrom(rootCfg)
 | 
				
			||||||
 | 
						loadRegisterMailFrom(rootCfg)
 | 
				
			||||||
 | 
						loadNotifyMailFrom(rootCfg)
 | 
				
			||||||
 | 
						loadIncomingEmailFrom(rootCfg)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func loadMailerFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	sec := rootCfg.Section("mailer")
 | 
						sec := rootCfg.Section("mailer")
 | 
				
			||||||
	// Check mailer setting.
 | 
						// Check mailer setting.
 | 
				
			||||||
	if !sec.Key("ENABLED").MustBool() {
 | 
						if !sec.Key("ENABLED").MustBool() {
 | 
				
			||||||
@@ -59,7 +65,7 @@ func parseMailerConfig(rootCfg *ini.File) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Handle Deprecations and map on to new configuration
 | 
						// Handle Deprecations and map on to new configuration
 | 
				
			||||||
	// FIXME: DEPRECATED to be removed in v1.19.0
 | 
						// FIXME: DEPRECATED to be removed in v1.19.0
 | 
				
			||||||
	deprecatedSetting("mailer", "MAILER_TYPE", "mailer", "PROTOCOL")
 | 
						deprecatedSetting(rootCfg, "mailer", "MAILER_TYPE", "mailer", "PROTOCOL")
 | 
				
			||||||
	if sec.HasKey("MAILER_TYPE") && !sec.HasKey("PROTOCOL") {
 | 
						if sec.HasKey("MAILER_TYPE") && !sec.HasKey("PROTOCOL") {
 | 
				
			||||||
		if sec.Key("MAILER_TYPE").String() == "sendmail" {
 | 
							if sec.Key("MAILER_TYPE").String() == "sendmail" {
 | 
				
			||||||
			sec.Key("PROTOCOL").MustString("sendmail")
 | 
								sec.Key("PROTOCOL").MustString("sendmail")
 | 
				
			||||||
@@ -67,7 +73,7 @@ func parseMailerConfig(rootCfg *ini.File) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// FIXME: DEPRECATED to be removed in v1.19.0
 | 
						// FIXME: DEPRECATED to be removed in v1.19.0
 | 
				
			||||||
	deprecatedSetting("mailer", "HOST", "mailer", "SMTP_ADDR")
 | 
						deprecatedSetting(rootCfg, "mailer", "HOST", "mailer", "SMTP_ADDR")
 | 
				
			||||||
	if sec.HasKey("HOST") && !sec.HasKey("SMTP_ADDR") {
 | 
						if sec.HasKey("HOST") && !sec.HasKey("SMTP_ADDR") {
 | 
				
			||||||
		givenHost := sec.Key("HOST").String()
 | 
							givenHost := sec.Key("HOST").String()
 | 
				
			||||||
		addr, port, err := net.SplitHostPort(givenHost)
 | 
							addr, port, err := net.SplitHostPort(givenHost)
 | 
				
			||||||
@@ -84,7 +90,7 @@ func parseMailerConfig(rootCfg *ini.File) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// FIXME: DEPRECATED to be removed in v1.19.0
 | 
						// FIXME: DEPRECATED to be removed in v1.19.0
 | 
				
			||||||
	deprecatedSetting("mailer", "IS_TLS_ENABLED", "mailer", "PROTOCOL")
 | 
						deprecatedSetting(rootCfg, "mailer", "IS_TLS_ENABLED", "mailer", "PROTOCOL")
 | 
				
			||||||
	if sec.HasKey("IS_TLS_ENABLED") && !sec.HasKey("PROTOCOL") {
 | 
						if sec.HasKey("IS_TLS_ENABLED") && !sec.HasKey("PROTOCOL") {
 | 
				
			||||||
		if sec.Key("IS_TLS_ENABLED").MustBool() {
 | 
							if sec.Key("IS_TLS_ENABLED").MustBool() {
 | 
				
			||||||
			sec.Key("PROTOCOL").MustString("smtps")
 | 
								sec.Key("PROTOCOL").MustString("smtps")
 | 
				
			||||||
@@ -94,37 +100,37 @@ func parseMailerConfig(rootCfg *ini.File) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// FIXME: DEPRECATED to be removed in v1.19.0
 | 
						// FIXME: DEPRECATED to be removed in v1.19.0
 | 
				
			||||||
	deprecatedSetting("mailer", "DISABLE_HELO", "mailer", "ENABLE_HELO")
 | 
						deprecatedSetting(rootCfg, "mailer", "DISABLE_HELO", "mailer", "ENABLE_HELO")
 | 
				
			||||||
	if sec.HasKey("DISABLE_HELO") && !sec.HasKey("ENABLE_HELO") {
 | 
						if sec.HasKey("DISABLE_HELO") && !sec.HasKey("ENABLE_HELO") {
 | 
				
			||||||
		sec.Key("ENABLE_HELO").MustBool(!sec.Key("DISABLE_HELO").MustBool())
 | 
							sec.Key("ENABLE_HELO").MustBool(!sec.Key("DISABLE_HELO").MustBool())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// FIXME: DEPRECATED to be removed in v1.19.0
 | 
						// FIXME: DEPRECATED to be removed in v1.19.0
 | 
				
			||||||
	deprecatedSetting("mailer", "SKIP_VERIFY", "mailer", "FORCE_TRUST_SERVER_CERT")
 | 
						deprecatedSetting(rootCfg, "mailer", "SKIP_VERIFY", "mailer", "FORCE_TRUST_SERVER_CERT")
 | 
				
			||||||
	if sec.HasKey("SKIP_VERIFY") && !sec.HasKey("FORCE_TRUST_SERVER_CERT") {
 | 
						if sec.HasKey("SKIP_VERIFY") && !sec.HasKey("FORCE_TRUST_SERVER_CERT") {
 | 
				
			||||||
		sec.Key("FORCE_TRUST_SERVER_CERT").MustBool(sec.Key("SKIP_VERIFY").MustBool())
 | 
							sec.Key("FORCE_TRUST_SERVER_CERT").MustBool(sec.Key("SKIP_VERIFY").MustBool())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// FIXME: DEPRECATED to be removed in v1.19.0
 | 
						// FIXME: DEPRECATED to be removed in v1.19.0
 | 
				
			||||||
	deprecatedSetting("mailer", "USE_CERTIFICATE", "mailer", "USE_CLIENT_CERT")
 | 
						deprecatedSetting(rootCfg, "mailer", "USE_CERTIFICATE", "mailer", "USE_CLIENT_CERT")
 | 
				
			||||||
	if sec.HasKey("USE_CERTIFICATE") && !sec.HasKey("USE_CLIENT_CERT") {
 | 
						if sec.HasKey("USE_CERTIFICATE") && !sec.HasKey("USE_CLIENT_CERT") {
 | 
				
			||||||
		sec.Key("USE_CLIENT_CERT").MustBool(sec.Key("USE_CERTIFICATE").MustBool())
 | 
							sec.Key("USE_CLIENT_CERT").MustBool(sec.Key("USE_CERTIFICATE").MustBool())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// FIXME: DEPRECATED to be removed in v1.19.0
 | 
						// FIXME: DEPRECATED to be removed in v1.19.0
 | 
				
			||||||
	deprecatedSetting("mailer", "CERT_FILE", "mailer", "CLIENT_CERT_FILE")
 | 
						deprecatedSetting(rootCfg, "mailer", "CERT_FILE", "mailer", "CLIENT_CERT_FILE")
 | 
				
			||||||
	if sec.HasKey("CERT_FILE") && !sec.HasKey("CLIENT_CERT_FILE") {
 | 
						if sec.HasKey("CERT_FILE") && !sec.HasKey("CLIENT_CERT_FILE") {
 | 
				
			||||||
		sec.Key("CERT_FILE").MustString(sec.Key("CERT_FILE").String())
 | 
							sec.Key("CERT_FILE").MustString(sec.Key("CERT_FILE").String())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// FIXME: DEPRECATED to be removed in v1.19.0
 | 
						// FIXME: DEPRECATED to be removed in v1.19.0
 | 
				
			||||||
	deprecatedSetting("mailer", "KEY_FILE", "mailer", "CLIENT_KEY_FILE")
 | 
						deprecatedSetting(rootCfg, "mailer", "KEY_FILE", "mailer", "CLIENT_KEY_FILE")
 | 
				
			||||||
	if sec.HasKey("KEY_FILE") && !sec.HasKey("CLIENT_KEY_FILE") {
 | 
						if sec.HasKey("KEY_FILE") && !sec.HasKey("CLIENT_KEY_FILE") {
 | 
				
			||||||
		sec.Key("KEY_FILE").MustString(sec.Key("KEY_FILE").String())
 | 
							sec.Key("KEY_FILE").MustString(sec.Key("KEY_FILE").String())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// FIXME: DEPRECATED to be removed in v1.19.0
 | 
						// FIXME: DEPRECATED to be removed in v1.19.0
 | 
				
			||||||
	deprecatedSetting("mailer", "ENABLE_HTML_ALTERNATIVE", "mailer", "SEND_AS_PLAIN_TEXT")
 | 
						deprecatedSetting(rootCfg, "mailer", "ENABLE_HTML_ALTERNATIVE", "mailer", "SEND_AS_PLAIN_TEXT")
 | 
				
			||||||
	if sec.HasKey("ENABLE_HTML_ALTERNATIVE") && !sec.HasKey("SEND_AS_PLAIN_TEXT") {
 | 
						if sec.HasKey("ENABLE_HTML_ALTERNATIVE") && !sec.HasKey("SEND_AS_PLAIN_TEXT") {
 | 
				
			||||||
		sec.Key("SEND_AS_PLAIN_TEXT").MustBool(!sec.Key("ENABLE_HTML_ALTERNATIVE").MustBool(false))
 | 
							sec.Key("SEND_AS_PLAIN_TEXT").MustBool(!sec.Key("ENABLE_HTML_ALTERNATIVE").MustBool(false))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -237,8 +243,8 @@ func parseMailerConfig(rootCfg *ini.File) {
 | 
				
			|||||||
	log.Info("Mail Service Enabled")
 | 
						log.Info("Mail Service Enabled")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newRegisterMailService() {
 | 
					func loadRegisterMailFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	if !Cfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").MustBool() {
 | 
						if !rootCfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").MustBool() {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	} else if MailService == nil {
 | 
						} else if MailService == nil {
 | 
				
			||||||
		log.Warn("Register Mail Service: Mail Service is not enabled")
 | 
							log.Warn("Register Mail Service: Mail Service is not enabled")
 | 
				
			||||||
@@ -248,8 +254,8 @@ func newRegisterMailService() {
 | 
				
			|||||||
	log.Info("Register Mail Service Enabled")
 | 
						log.Info("Register Mail Service Enabled")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newNotifyMailService() {
 | 
					func loadNotifyMailFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	if !Cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").MustBool() {
 | 
						if !rootCfg.Section("service").Key("ENABLE_NOTIFY_MAIL").MustBool() {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	} else if MailService == nil {
 | 
						} else if MailService == nil {
 | 
				
			||||||
		log.Warn("Notify Mail Service: Mail Service is not enabled")
 | 
							log.Warn("Notify Mail Service: Mail Service is not enabled")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,7 @@ import (
 | 
				
			|||||||
	ini "gopkg.in/ini.v1"
 | 
						ini "gopkg.in/ini.v1"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestParseMailerConfig(t *testing.T) {
 | 
					func Test_loadMailerFrom(t *testing.T) {
 | 
				
			||||||
	iniFile := ini.Empty()
 | 
						iniFile := ini.Empty()
 | 
				
			||||||
	kases := map[string]*Mailer{
 | 
						kases := map[string]*Mailer{
 | 
				
			||||||
		"smtp.mydomain.com": {
 | 
							"smtp.mydomain.com": {
 | 
				
			||||||
@@ -34,7 +34,7 @@ func TestParseMailerConfig(t *testing.T) {
 | 
				
			|||||||
			sec.NewKey("HOST", host)
 | 
								sec.NewKey("HOST", host)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Check mailer setting
 | 
								// Check mailer setting
 | 
				
			||||||
			parseMailerConfig(iniFile)
 | 
								loadMailerFrom(iniFile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			assert.EqualValues(t, kase.SMTPAddr, MailService.SMTPAddr)
 | 
								assert.EqualValues(t, kase.SMTPAddr, MailService.SMTPAddr)
 | 
				
			||||||
			assert.EqualValues(t, kase.SMTPPort, MailService.SMTPPort)
 | 
								assert.EqualValues(t, kase.SMTPPort, MailService.SMTPPort)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,6 +25,20 @@ const (
 | 
				
			|||||||
	RenderContentModeIframe      = "iframe"
 | 
						RenderContentModeIframe      = "iframe"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Markdown settings
 | 
				
			||||||
 | 
					var Markdown = struct {
 | 
				
			||||||
 | 
						EnableHardLineBreakInComments  bool
 | 
				
			||||||
 | 
						EnableHardLineBreakInDocuments bool
 | 
				
			||||||
 | 
						CustomURLSchemes               []string `ini:"CUSTOM_URL_SCHEMES"`
 | 
				
			||||||
 | 
						FileExtensions                 []string
 | 
				
			||||||
 | 
						EnableMath                     bool
 | 
				
			||||||
 | 
					}{
 | 
				
			||||||
 | 
						EnableHardLineBreakInComments:  true,
 | 
				
			||||||
 | 
						EnableHardLineBreakInDocuments: false,
 | 
				
			||||||
 | 
						FileExtensions:                 strings.Split(".md,.markdown,.mdown,.mkd", ","),
 | 
				
			||||||
 | 
						EnableMath:                     true,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// MarkupRenderer defines the external parser configured in ini
 | 
					// MarkupRenderer defines the external parser configured in ini
 | 
				
			||||||
type MarkupRenderer struct {
 | 
					type MarkupRenderer struct {
 | 
				
			||||||
	Enabled              bool
 | 
						Enabled              bool
 | 
				
			||||||
@@ -46,12 +60,14 @@ type MarkupSanitizerRule struct {
 | 
				
			|||||||
	AllowDataURIImages bool
 | 
						AllowDataURIImages bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newMarkup() {
 | 
					func loadMarkupFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	MermaidMaxSourceCharacters = Cfg.Section("markup").Key("MERMAID_MAX_SOURCE_CHARACTERS").MustInt(5000)
 | 
						mustMapSetting(rootCfg, "markdown", &Markdown)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						MermaidMaxSourceCharacters = rootCfg.Section("markup").Key("MERMAID_MAX_SOURCE_CHARACTERS").MustInt(5000)
 | 
				
			||||||
	ExternalMarkupRenderers = make([]*MarkupRenderer, 0, 10)
 | 
						ExternalMarkupRenderers = make([]*MarkupRenderer, 0, 10)
 | 
				
			||||||
	ExternalSanitizerRules = make([]MarkupSanitizerRule, 0, 10)
 | 
						ExternalSanitizerRules = make([]MarkupSanitizerRule, 0, 10)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, sec := range Cfg.Section("markup").ChildSections() {
 | 
						for _, sec := range rootCfg.Section("markup").ChildSections() {
 | 
				
			||||||
		name := strings.TrimPrefix(sec.Name(), "markup.")
 | 
							name := strings.TrimPrefix(sec.Name(), "markup.")
 | 
				
			||||||
		if name == "" {
 | 
							if name == "" {
 | 
				
			||||||
			log.Warn("name is empty, markup " + sec.Name() + "ignored")
 | 
								log.Warn("name is empty, markup " + sec.Name() + "ignored")
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										21
									
								
								modules/setting/metrics.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								modules/setting/metrics.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					// Copyright 2023 The Gitea Authors. All rights reserved.
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: MIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package setting
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Metrics settings
 | 
				
			||||||
 | 
					var Metrics = struct {
 | 
				
			||||||
 | 
						Enabled                  bool
 | 
				
			||||||
 | 
						Token                    string
 | 
				
			||||||
 | 
						EnabledIssueByLabel      bool
 | 
				
			||||||
 | 
						EnabledIssueByRepository bool
 | 
				
			||||||
 | 
					}{
 | 
				
			||||||
 | 
						Enabled:                  false,
 | 
				
			||||||
 | 
						Token:                    "",
 | 
				
			||||||
 | 
						EnabledIssueByLabel:      false,
 | 
				
			||||||
 | 
						EnabledIssueByRepository: false,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func loadMetricsFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
 | 
						mustMapSetting(rootCfg, "metrics", &Metrics)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -16,8 +16,8 @@ var Migrations = struct {
 | 
				
			|||||||
	RetryBackoff: 3,
 | 
						RetryBackoff: 3,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newMigrationsService() {
 | 
					func loadMigrationsFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	sec := Cfg.Section("migrations")
 | 
						sec := rootCfg.Section("migrations")
 | 
				
			||||||
	Migrations.MaxAttempts = sec.Key("MAX_ATTEMPTS").MustInt(Migrations.MaxAttempts)
 | 
						Migrations.MaxAttempts = sec.Key("MAX_ATTEMPTS").MustInt(Migrations.MaxAttempts)
 | 
				
			||||||
	Migrations.RetryBackoff = sec.Key("RETRY_BACKOFF").MustInt(Migrations.RetryBackoff)
 | 
						Migrations.RetryBackoff = sec.Key("RETRY_BACKOFF").MustInt(Migrations.RetryBackoff)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,8 +14,8 @@ var MimeTypeMap = struct {
 | 
				
			|||||||
	Map:     map[string]string{},
 | 
						Map:     map[string]string{},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newMimeTypeMap() {
 | 
					func loadMimeTypeMapFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	sec := Cfg.Section("repository.mimetype_mapping")
 | 
						sec := rootCfg.Section("repository.mimetype_mapping")
 | 
				
			||||||
	keys := sec.Keys()
 | 
						keys := sec.Keys()
 | 
				
			||||||
	m := make(map[string]string, len(keys))
 | 
						m := make(map[string]string, len(keys))
 | 
				
			||||||
	for _, key := range keys {
 | 
						for _, key := range keys {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,16 +24,16 @@ var Mirror = struct {
 | 
				
			|||||||
	DefaultInterval: 8 * time.Hour,
 | 
						DefaultInterval: 8 * time.Hour,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newMirror() {
 | 
					func loadMirrorFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	// Handle old configuration through `[repository]` `DISABLE_MIRRORS`
 | 
						// Handle old configuration through `[repository]` `DISABLE_MIRRORS`
 | 
				
			||||||
	// - please note this was badly named and only disabled the creation of new pull mirrors
 | 
						// - please note this was badly named and only disabled the creation of new pull mirrors
 | 
				
			||||||
	// FIXME: DEPRECATED to be removed in v1.18.0
 | 
						// FIXME: DEPRECATED to be removed in v1.18.0
 | 
				
			||||||
	deprecatedSetting("repository", "DISABLE_MIRRORS", "mirror", "ENABLED")
 | 
						deprecatedSetting(rootCfg, "repository", "DISABLE_MIRRORS", "mirror", "ENABLED")
 | 
				
			||||||
	if Cfg.Section("repository").Key("DISABLE_MIRRORS").MustBool(false) {
 | 
						if rootCfg.Section("repository").Key("DISABLE_MIRRORS").MustBool(false) {
 | 
				
			||||||
		Mirror.DisableNewPull = true
 | 
							Mirror.DisableNewPull = true
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := Cfg.Section("mirror").MapTo(&Mirror); err != nil {
 | 
						if err := rootCfg.Section("mirror").MapTo(&Mirror); err != nil {
 | 
				
			||||||
		log.Fatal("Failed to map Mirror settings: %v", err)
 | 
							log.Fatal("Failed to map Mirror settings: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,9 @@
 | 
				
			|||||||
package setting
 | 
					package setting
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"math"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/modules/log"
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"gopkg.in/ini.v1"
 | 
						"gopkg.in/ini.v1"
 | 
				
			||||||
@@ -59,8 +62,8 @@ var OAuth2Client struct {
 | 
				
			|||||||
	AccountLinking         OAuth2AccountLinkingType
 | 
						AccountLinking         OAuth2AccountLinkingType
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newOAuth2Client() {
 | 
					func loadOAuth2ClientFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	sec := Cfg.Section("oauth2_client")
 | 
						sec := rootCfg.Section("oauth2_client")
 | 
				
			||||||
	OAuth2Client.RegisterEmailConfirm = sec.Key("REGISTER_EMAIL_CONFIRM").MustBool(Service.RegisterEmailConfirm)
 | 
						OAuth2Client.RegisterEmailConfirm = sec.Key("REGISTER_EMAIL_CONFIRM").MustBool(Service.RegisterEmailConfirm)
 | 
				
			||||||
	OAuth2Client.OpenIDConnectScopes = parseScopes(sec, "OPENID_CONNECT_SCOPES")
 | 
						OAuth2Client.OpenIDConnectScopes = parseScopes(sec, "OPENID_CONNECT_SCOPES")
 | 
				
			||||||
	OAuth2Client.EnableAutoRegistration = sec.Key("ENABLE_AUTO_REGISTRATION").MustBool()
 | 
						OAuth2Client.EnableAutoRegistration = sec.Key("ENABLE_AUTO_REGISTRATION").MustBool()
 | 
				
			||||||
@@ -87,3 +90,33 @@ func parseScopes(sec *ini.Section, name string) []string {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return scopes
 | 
						return scopes
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var OAuth2 = struct {
 | 
				
			||||||
 | 
						Enable                     bool
 | 
				
			||||||
 | 
						AccessTokenExpirationTime  int64
 | 
				
			||||||
 | 
						RefreshTokenExpirationTime int64
 | 
				
			||||||
 | 
						InvalidateRefreshTokens    bool
 | 
				
			||||||
 | 
						JWTSigningAlgorithm        string `ini:"JWT_SIGNING_ALGORITHM"`
 | 
				
			||||||
 | 
						JWTSecretBase64            string `ini:"JWT_SECRET"`
 | 
				
			||||||
 | 
						JWTSigningPrivateKeyFile   string `ini:"JWT_SIGNING_PRIVATE_KEY_FILE"`
 | 
				
			||||||
 | 
						MaxTokenLength             int
 | 
				
			||||||
 | 
					}{
 | 
				
			||||||
 | 
						Enable:                     true,
 | 
				
			||||||
 | 
						AccessTokenExpirationTime:  3600,
 | 
				
			||||||
 | 
						RefreshTokenExpirationTime: 730,
 | 
				
			||||||
 | 
						InvalidateRefreshTokens:    false,
 | 
				
			||||||
 | 
						JWTSigningAlgorithm:        "RS256",
 | 
				
			||||||
 | 
						JWTSigningPrivateKeyFile:   "jwt/private.pem",
 | 
				
			||||||
 | 
						MaxTokenLength:             math.MaxInt16,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func loadOAuth2From(rootCfg ConfigProvider) {
 | 
				
			||||||
 | 
						if err := rootCfg.Section("oauth2").MapTo(&OAuth2); err != nil {
 | 
				
			||||||
 | 
							log.Fatal("Failed to OAuth2 settings: %v", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !filepath.IsAbs(OAuth2.JWTSigningPrivateKeyFile) {
 | 
				
			||||||
 | 
							OAuth2.JWTSigningPrivateKeyFile = filepath.Join(AppDataPath, OAuth2.JWTSigningPrivateKeyFile)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										22
									
								
								modules/setting/other.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								modules/setting/other.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					// Copyright 2023 The Gitea Authors. All rights reserved.
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: MIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package setting
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						// Other settings
 | 
				
			||||||
 | 
						ShowFooterBranding         bool
 | 
				
			||||||
 | 
						ShowFooterVersion          bool
 | 
				
			||||||
 | 
						ShowFooterTemplateLoadTime bool
 | 
				
			||||||
 | 
						EnableFeed                 bool
 | 
				
			||||||
 | 
						EnableSitemap              bool
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func loadOtherFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
 | 
						sec := rootCfg.Section("other")
 | 
				
			||||||
 | 
						ShowFooterBranding = sec.Key("SHOW_FOOTER_BRANDING").MustBool(false)
 | 
				
			||||||
 | 
						ShowFooterVersion = sec.Key("SHOW_FOOTER_VERSION").MustBool(true)
 | 
				
			||||||
 | 
						ShowFooterTemplateLoadTime = sec.Key("SHOW_FOOTER_TEMPLATE_LOAD_TIME").MustBool(true)
 | 
				
			||||||
 | 
						EnableSitemap = sec.Key("ENABLE_SITEMAP").MustBool(true)
 | 
				
			||||||
 | 
						EnableFeed = sec.Key("ENABLE_FEED").MustBool(true)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -46,13 +46,13 @@ var (
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newPackages() {
 | 
					func loadPackagesFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	sec := Cfg.Section("packages")
 | 
						sec := rootCfg.Section("packages")
 | 
				
			||||||
	if err := sec.MapTo(&Packages); err != nil {
 | 
						if err := sec.MapTo(&Packages); err != nil {
 | 
				
			||||||
		log.Fatal("Failed to map Packages settings: %v", err)
 | 
							log.Fatal("Failed to map Packages settings: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Packages.Storage = getStorage("packages", "", nil)
 | 
						Packages.Storage = getStorage(rootCfg, "packages", "", nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	appURL, _ := url.Parse(AppURL)
 | 
						appURL, _ := url.Parse(AppURL)
 | 
				
			||||||
	Packages.RegistryHost = appURL.Host
 | 
						Packages.RegistryHost = appURL.Host
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,16 +32,16 @@ var (
 | 
				
			|||||||
	}{}
 | 
						}{}
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newPictureService() {
 | 
					func loadPictureFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	sec := Cfg.Section("picture")
 | 
						sec := rootCfg.Section("picture")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	avatarSec := Cfg.Section("avatar")
 | 
						avatarSec := rootCfg.Section("avatar")
 | 
				
			||||||
	storageType := sec.Key("AVATAR_STORAGE_TYPE").MustString("")
 | 
						storageType := sec.Key("AVATAR_STORAGE_TYPE").MustString("")
 | 
				
			||||||
	// Specifically default PATH to AVATAR_UPLOAD_PATH
 | 
						// Specifically default PATH to AVATAR_UPLOAD_PATH
 | 
				
			||||||
	avatarSec.Key("PATH").MustString(
 | 
						avatarSec.Key("PATH").MustString(
 | 
				
			||||||
		sec.Key("AVATAR_UPLOAD_PATH").String())
 | 
							sec.Key("AVATAR_UPLOAD_PATH").String())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Avatar.Storage = getStorage("avatars", storageType, avatarSec)
 | 
						Avatar.Storage = getStorage(rootCfg, "avatars", storageType, avatarSec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Avatar.MaxWidth = sec.Key("AVATAR_MAX_WIDTH").MustInt(4096)
 | 
						Avatar.MaxWidth = sec.Key("AVATAR_MAX_WIDTH").MustInt(4096)
 | 
				
			||||||
	Avatar.MaxHeight = sec.Key("AVATAR_MAX_HEIGHT").MustInt(3072)
 | 
						Avatar.MaxHeight = sec.Key("AVATAR_MAX_HEIGHT").MustInt(3072)
 | 
				
			||||||
@@ -60,11 +60,11 @@ func newPictureService() {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	DisableGravatar = sec.Key("DISABLE_GRAVATAR").MustBool(GetDefaultDisableGravatar())
 | 
						DisableGravatar = sec.Key("DISABLE_GRAVATAR").MustBool(GetDefaultDisableGravatar())
 | 
				
			||||||
	deprecatedSettingDB("", "DISABLE_GRAVATAR")
 | 
						deprecatedSettingDB(rootCfg, "", "DISABLE_GRAVATAR")
 | 
				
			||||||
	EnableFederatedAvatar = sec.Key("ENABLE_FEDERATED_AVATAR").MustBool(GetDefaultEnableFederatedAvatar(DisableGravatar))
 | 
						EnableFederatedAvatar = sec.Key("ENABLE_FEDERATED_AVATAR").MustBool(GetDefaultEnableFederatedAvatar(DisableGravatar))
 | 
				
			||||||
	deprecatedSettingDB("", "ENABLE_FEDERATED_AVATAR")
 | 
						deprecatedSettingDB(rootCfg, "", "ENABLE_FEDERATED_AVATAR")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	newRepoAvatarService()
 | 
						loadRepoAvatarFrom(rootCfg)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func GetDefaultDisableGravatar() bool {
 | 
					func GetDefaultDisableGravatar() bool {
 | 
				
			||||||
@@ -82,16 +82,16 @@ func GetDefaultEnableFederatedAvatar(disableGravatar bool) bool {
 | 
				
			|||||||
	return v
 | 
						return v
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newRepoAvatarService() {
 | 
					func loadRepoAvatarFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	sec := Cfg.Section("picture")
 | 
						sec := rootCfg.Section("picture")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	repoAvatarSec := Cfg.Section("repo-avatar")
 | 
						repoAvatarSec := rootCfg.Section("repo-avatar")
 | 
				
			||||||
	storageType := sec.Key("REPOSITORY_AVATAR_STORAGE_TYPE").MustString("")
 | 
						storageType := sec.Key("REPOSITORY_AVATAR_STORAGE_TYPE").MustString("")
 | 
				
			||||||
	// Specifically default PATH to AVATAR_UPLOAD_PATH
 | 
						// Specifically default PATH to AVATAR_UPLOAD_PATH
 | 
				
			||||||
	repoAvatarSec.Key("PATH").MustString(
 | 
						repoAvatarSec.Key("PATH").MustString(
 | 
				
			||||||
		sec.Key("REPOSITORY_AVATAR_UPLOAD_PATH").String())
 | 
							sec.Key("REPOSITORY_AVATAR_UPLOAD_PATH").String())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	RepoAvatar.Storage = getStorage("repo-avatars", storageType, repoAvatarSec)
 | 
						RepoAvatar.Storage = getStorage(rootCfg, "repo-avatars", storageType, repoAvatarSec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	RepoAvatar.Fallback = sec.Key("REPOSITORY_AVATAR_FALLBACK").MustString("none")
 | 
						RepoAvatar.Fallback = sec.Key("REPOSITORY_AVATAR_FALLBACK").MustString("none")
 | 
				
			||||||
	RepoAvatar.FallbackImage = sec.Key("REPOSITORY_AVATAR_FALLBACK_IMAGE").MustString("/assets/img/repo_default.png")
 | 
						RepoAvatar.FallbackImage = sec.Key("REPOSITORY_AVATAR_FALLBACK_IMAGE").MustString("/assets/img/repo_default.png")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,8 +3,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package setting
 | 
					package setting
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "code.gitea.io/gitea/modules/log"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Project settings
 | 
					// Project settings
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
	Project = struct {
 | 
						Project = struct {
 | 
				
			||||||
@@ -16,8 +14,6 @@ var (
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newProject() {
 | 
					func loadProjectFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	if err := Cfg.Section("project").MapTo(&Project); err != nil {
 | 
						mustMapSetting(rootCfg, "project", &Project)
 | 
				
			||||||
		log.Fatal("Failed to map Project settings: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,8 +21,8 @@ var Proxy = struct {
 | 
				
			|||||||
	ProxyHosts: []string{},
 | 
						ProxyHosts: []string{},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newProxyService() {
 | 
					func loadProxyFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	sec := Cfg.Section("proxy")
 | 
						sec := rootCfg.Section("proxy")
 | 
				
			||||||
	Proxy.Enabled = sec.Key("PROXY_ENABLED").MustBool(false)
 | 
						Proxy.Enabled = sec.Key("PROXY_ENABLED").MustBool(false)
 | 
				
			||||||
	Proxy.ProxyURL = sec.Key("PROXY_URL").MustString("")
 | 
						Proxy.ProxyURL = sec.Key("PROXY_URL").MustString("")
 | 
				
			||||||
	if Proxy.ProxyURL != "" {
 | 
						if Proxy.ProxyURL != "" {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,8 +39,12 @@ var Queue = QueueSettings{}
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// GetQueueSettings returns the queue settings for the appropriately named queue
 | 
					// GetQueueSettings returns the queue settings for the appropriately named queue
 | 
				
			||||||
func GetQueueSettings(name string) QueueSettings {
 | 
					func GetQueueSettings(name string) QueueSettings {
 | 
				
			||||||
 | 
						return getQueueSettings(CfgProvider, name)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getQueueSettings(rootCfg ConfigProvider, name string) QueueSettings {
 | 
				
			||||||
	q := QueueSettings{}
 | 
						q := QueueSettings{}
 | 
				
			||||||
	sec := Cfg.Section("queue." + name)
 | 
						sec := rootCfg.Section("queue." + name)
 | 
				
			||||||
	q.Name = name
 | 
						q.Name = name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// DataDir is not directly inheritable
 | 
						// DataDir is not directly inheritable
 | 
				
			||||||
@@ -82,10 +86,14 @@ func GetQueueSettings(name string) QueueSettings {
 | 
				
			|||||||
	return q
 | 
						return q
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewQueueService sets up the default settings for Queues
 | 
					// LoadQueueSettings sets up the default settings for Queues
 | 
				
			||||||
// This is exported for tests to be able to use the queue
 | 
					// This is exported for tests to be able to use the queue
 | 
				
			||||||
func NewQueueService() {
 | 
					func LoadQueueSettings() {
 | 
				
			||||||
	sec := Cfg.Section("queue")
 | 
						loadQueueFrom(CfgProvider)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func loadQueueFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
 | 
						sec := rootCfg.Section("queue")
 | 
				
			||||||
	Queue.DataDir = filepath.ToSlash(sec.Key("DATADIR").MustString("queues/"))
 | 
						Queue.DataDir = filepath.ToSlash(sec.Key("DATADIR").MustString("queues/"))
 | 
				
			||||||
	if !filepath.IsAbs(Queue.DataDir) {
 | 
						if !filepath.IsAbs(Queue.DataDir) {
 | 
				
			||||||
		Queue.DataDir = filepath.ToSlash(filepath.Join(AppDataPath, Queue.DataDir))
 | 
							Queue.DataDir = filepath.ToSlash(filepath.Join(AppDataPath, Queue.DataDir))
 | 
				
			||||||
@@ -108,10 +116,10 @@ func NewQueueService() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Now handle the old issue_indexer configuration
 | 
						// Now handle the old issue_indexer configuration
 | 
				
			||||||
	// FIXME: DEPRECATED to be removed in v1.18.0
 | 
						// FIXME: DEPRECATED to be removed in v1.18.0
 | 
				
			||||||
	section := Cfg.Section("queue.issue_indexer")
 | 
						section := rootCfg.Section("queue.issue_indexer")
 | 
				
			||||||
	directlySet := toDirectlySetKeysSet(section)
 | 
						directlySet := toDirectlySetKeysSet(section)
 | 
				
			||||||
	if !directlySet.Contains("TYPE") && defaultType == "" {
 | 
						if !directlySet.Contains("TYPE") && defaultType == "" {
 | 
				
			||||||
		switch typ := Cfg.Section("indexer").Key("ISSUE_INDEXER_QUEUE_TYPE").MustString(""); typ {
 | 
							switch typ := rootCfg.Section("indexer").Key("ISSUE_INDEXER_QUEUE_TYPE").MustString(""); typ {
 | 
				
			||||||
		case "levelqueue":
 | 
							case "levelqueue":
 | 
				
			||||||
			_, _ = section.NewKey("TYPE", "level")
 | 
								_, _ = section.NewKey("TYPE", "level")
 | 
				
			||||||
		case "channel":
 | 
							case "channel":
 | 
				
			||||||
@@ -125,25 +133,25 @@ func NewQueueService() {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !directlySet.Contains("LENGTH") {
 | 
						if !directlySet.Contains("LENGTH") {
 | 
				
			||||||
		length := Cfg.Section("indexer").Key("UPDATE_BUFFER_LEN").MustInt(0)
 | 
							length := rootCfg.Section("indexer").Key("UPDATE_BUFFER_LEN").MustInt(0)
 | 
				
			||||||
		if length != 0 {
 | 
							if length != 0 {
 | 
				
			||||||
			_, _ = section.NewKey("LENGTH", strconv.Itoa(length))
 | 
								_, _ = section.NewKey("LENGTH", strconv.Itoa(length))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !directlySet.Contains("BATCH_LENGTH") {
 | 
						if !directlySet.Contains("BATCH_LENGTH") {
 | 
				
			||||||
		fallback := Cfg.Section("indexer").Key("ISSUE_INDEXER_QUEUE_BATCH_NUMBER").MustInt(0)
 | 
							fallback := rootCfg.Section("indexer").Key("ISSUE_INDEXER_QUEUE_BATCH_NUMBER").MustInt(0)
 | 
				
			||||||
		if fallback != 0 {
 | 
							if fallback != 0 {
 | 
				
			||||||
			_, _ = section.NewKey("BATCH_LENGTH", strconv.Itoa(fallback))
 | 
								_, _ = section.NewKey("BATCH_LENGTH", strconv.Itoa(fallback))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !directlySet.Contains("DATADIR") {
 | 
						if !directlySet.Contains("DATADIR") {
 | 
				
			||||||
		queueDir := filepath.ToSlash(Cfg.Section("indexer").Key("ISSUE_INDEXER_QUEUE_DIR").MustString(""))
 | 
							queueDir := filepath.ToSlash(rootCfg.Section("indexer").Key("ISSUE_INDEXER_QUEUE_DIR").MustString(""))
 | 
				
			||||||
		if queueDir != "" {
 | 
							if queueDir != "" {
 | 
				
			||||||
			_, _ = section.NewKey("DATADIR", queueDir)
 | 
								_, _ = section.NewKey("DATADIR", queueDir)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !directlySet.Contains("CONN_STR") {
 | 
						if !directlySet.Contains("CONN_STR") {
 | 
				
			||||||
		connStr := Cfg.Section("indexer").Key("ISSUE_INDEXER_QUEUE_CONN_STR").MustString("")
 | 
							connStr := rootCfg.Section("indexer").Key("ISSUE_INDEXER_QUEUE_CONN_STR").MustString("")
 | 
				
			||||||
		if connStr != "" {
 | 
							if connStr != "" {
 | 
				
			||||||
			_, _ = section.NewKey("CONN_STR", connStr)
 | 
								_, _ = section.NewKey("CONN_STR", connStr)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -153,31 +161,31 @@ func NewQueueService() {
 | 
				
			|||||||
	// - will need to set default for [queue.*)] LENGTH appropriately though though
 | 
						// - will need to set default for [queue.*)] LENGTH appropriately though though
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Handle the old mailer configuration
 | 
						// Handle the old mailer configuration
 | 
				
			||||||
	handleOldLengthConfiguration("mailer", "mailer", "SEND_BUFFER_LEN", 100)
 | 
						handleOldLengthConfiguration(rootCfg, "mailer", "mailer", "SEND_BUFFER_LEN", 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Handle the old test pull requests configuration
 | 
						// Handle the old test pull requests configuration
 | 
				
			||||||
	// Please note this will be a unique queue
 | 
						// Please note this will be a unique queue
 | 
				
			||||||
	handleOldLengthConfiguration("pr_patch_checker", "repository", "PULL_REQUEST_QUEUE_LENGTH", 1000)
 | 
						handleOldLengthConfiguration(rootCfg, "pr_patch_checker", "repository", "PULL_REQUEST_QUEUE_LENGTH", 1000)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Handle the old mirror queue configuration
 | 
						// Handle the old mirror queue configuration
 | 
				
			||||||
	// Please note this will be a unique queue
 | 
						// Please note this will be a unique queue
 | 
				
			||||||
	handleOldLengthConfiguration("mirror", "repository", "MIRROR_QUEUE_LENGTH", 1000)
 | 
						handleOldLengthConfiguration(rootCfg, "mirror", "repository", "MIRROR_QUEUE_LENGTH", 1000)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// handleOldLengthConfiguration allows fallback to older configuration. `[queue.name]` `LENGTH` will override this configuration, but
 | 
					// handleOldLengthConfiguration allows fallback to older configuration. `[queue.name]` `LENGTH` will override this configuration, but
 | 
				
			||||||
// if that is left unset then we should fallback to the older configuration. (Except where the new length woul be <=0)
 | 
					// if that is left unset then we should fallback to the older configuration. (Except where the new length woul be <=0)
 | 
				
			||||||
func handleOldLengthConfiguration(queueName, oldSection, oldKey string, defaultValue int) {
 | 
					func handleOldLengthConfiguration(rootCfg ConfigProvider, queueName, oldSection, oldKey string, defaultValue int) {
 | 
				
			||||||
	if Cfg.Section(oldSection).HasKey(oldKey) {
 | 
						if rootCfg.Section(oldSection).HasKey(oldKey) {
 | 
				
			||||||
		log.Error("Deprecated fallback for %s queue length `[%s]` `%s` present. Use `[queue.%s]` `LENGTH`. This will be removed in v1.18.0", queueName, queueName, oldSection, oldKey)
 | 
							log.Error("Deprecated fallback for %s queue length `[%s]` `%s` present. Use `[queue.%s]` `LENGTH`. This will be removed in v1.18.0", queueName, queueName, oldSection, oldKey)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	value := Cfg.Section(oldSection).Key(oldKey).MustInt(defaultValue)
 | 
						value := rootCfg.Section(oldSection).Key(oldKey).MustInt(defaultValue)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Don't override with 0
 | 
						// Don't override with 0
 | 
				
			||||||
	if value <= 0 {
 | 
						if value <= 0 {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	section := Cfg.Section("queue." + queueName)
 | 
						section := rootCfg.Section("queue." + queueName)
 | 
				
			||||||
	directlySet := toDirectlySetKeysSet(section)
 | 
						directlySet := toDirectlySetKeysSet(section)
 | 
				
			||||||
	if !directlySet.Contains("LENGTH") {
 | 
						if !directlySet.Contains("LENGTH") {
 | 
				
			||||||
		_, _ = section.NewKey("LENGTH", strconv.Itoa(value))
 | 
							_, _ = section.NewKey("LENGTH", strconv.Itoa(value))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -270,10 +270,10 @@ var (
 | 
				
			|||||||
	}{}
 | 
						}{}
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newRepository() {
 | 
					func loadRepositoryFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	var err error
 | 
						var err error
 | 
				
			||||||
	// Determine and create root git repository path.
 | 
						// Determine and create root git repository path.
 | 
				
			||||||
	sec := Cfg.Section("repository")
 | 
						sec := rootCfg.Section("repository")
 | 
				
			||||||
	Repository.DisableHTTPGit = sec.Key("DISABLE_HTTP_GIT").MustBool()
 | 
						Repository.DisableHTTPGit = sec.Key("DISABLE_HTTP_GIT").MustBool()
 | 
				
			||||||
	Repository.UseCompatSSHURI = sec.Key("USE_COMPAT_SSH_URI").MustBool()
 | 
						Repository.UseCompatSSHURI = sec.Key("USE_COMPAT_SSH_URI").MustBool()
 | 
				
			||||||
	Repository.MaxCreationLimit = sec.Key("MAX_CREATION_LIMIT").MustInt(-1)
 | 
						Repository.MaxCreationLimit = sec.Key("MAX_CREATION_LIMIT").MustInt(-1)
 | 
				
			||||||
@@ -295,19 +295,19 @@ func newRepository() {
 | 
				
			|||||||
		log.Warn("SCRIPT_TYPE %q is not on the current PATH. Are you sure that this is the correct SCRIPT_TYPE?", ScriptType)
 | 
							log.Warn("SCRIPT_TYPE %q is not on the current PATH. Are you sure that this is the correct SCRIPT_TYPE?", ScriptType)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err = Cfg.Section("repository").MapTo(&Repository); err != nil {
 | 
						if err = sec.MapTo(&Repository); err != nil {
 | 
				
			||||||
		log.Fatal("Failed to map Repository settings: %v", err)
 | 
							log.Fatal("Failed to map Repository settings: %v", err)
 | 
				
			||||||
	} else if err = Cfg.Section("repository.editor").MapTo(&Repository.Editor); err != nil {
 | 
						} else if err = rootCfg.Section("repository.editor").MapTo(&Repository.Editor); err != nil {
 | 
				
			||||||
		log.Fatal("Failed to map Repository.Editor settings: %v", err)
 | 
							log.Fatal("Failed to map Repository.Editor settings: %v", err)
 | 
				
			||||||
	} else if err = Cfg.Section("repository.upload").MapTo(&Repository.Upload); err != nil {
 | 
						} else if err = rootCfg.Section("repository.upload").MapTo(&Repository.Upload); err != nil {
 | 
				
			||||||
		log.Fatal("Failed to map Repository.Upload settings: %v", err)
 | 
							log.Fatal("Failed to map Repository.Upload settings: %v", err)
 | 
				
			||||||
	} else if err = Cfg.Section("repository.local").MapTo(&Repository.Local); err != nil {
 | 
						} else if err = rootCfg.Section("repository.local").MapTo(&Repository.Local); err != nil {
 | 
				
			||||||
		log.Fatal("Failed to map Repository.Local settings: %v", err)
 | 
							log.Fatal("Failed to map Repository.Local settings: %v", err)
 | 
				
			||||||
	} else if err = Cfg.Section("repository.pull-request").MapTo(&Repository.PullRequest); err != nil {
 | 
						} else if err = rootCfg.Section("repository.pull-request").MapTo(&Repository.PullRequest); err != nil {
 | 
				
			||||||
		log.Fatal("Failed to map Repository.PullRequest settings: %v", err)
 | 
							log.Fatal("Failed to map Repository.PullRequest settings: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if !Cfg.Section("packages").Key("ENABLED").MustBool(true) {
 | 
						if !rootCfg.Section("packages").Key("ENABLED").MustBool(true) {
 | 
				
			||||||
		Repository.DisabledRepoUnits = append(Repository.DisabledRepoUnits, "repo.packages")
 | 
							Repository.DisabledRepoUnits = append(Repository.DisabledRepoUnits, "repo.packages")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -354,5 +354,5 @@ func newRepository() {
 | 
				
			|||||||
		Repository.Upload.TempPath = path.Join(AppWorkPath, Repository.Upload.TempPath)
 | 
							Repository.Upload.TempPath = path.Join(AppWorkPath, Repository.Upload.TempPath)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	RepoArchive.Storage = getStorage("repo-archive", "", nil)
 | 
						RepoArchive.Storage = getStorage(rootCfg, "repo-archive", "", nil)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										158
									
								
								modules/setting/security.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								modules/setting/security.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,158 @@
 | 
				
			|||||||
 | 
					// Copyright 2023 The Gitea Authors. All rights reserved.
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: MIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package setting
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/auth/password/hash"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/generate"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ini "gopkg.in/ini.v1"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						// Security settings
 | 
				
			||||||
 | 
						InstallLock                        bool
 | 
				
			||||||
 | 
						SecretKey                          string
 | 
				
			||||||
 | 
						InternalToken                      string // internal access token
 | 
				
			||||||
 | 
						LogInRememberDays                  int
 | 
				
			||||||
 | 
						CookieUserName                     string
 | 
				
			||||||
 | 
						CookieRememberName                 string
 | 
				
			||||||
 | 
						ReverseProxyAuthUser               string
 | 
				
			||||||
 | 
						ReverseProxyAuthEmail              string
 | 
				
			||||||
 | 
						ReverseProxyAuthFullName           string
 | 
				
			||||||
 | 
						ReverseProxyLimit                  int
 | 
				
			||||||
 | 
						ReverseProxyTrustedProxies         []string
 | 
				
			||||||
 | 
						MinPasswordLength                  int
 | 
				
			||||||
 | 
						ImportLocalPaths                   bool
 | 
				
			||||||
 | 
						DisableGitHooks                    bool
 | 
				
			||||||
 | 
						DisableWebhooks                    bool
 | 
				
			||||||
 | 
						OnlyAllowPushIfGiteaEnvironmentSet bool
 | 
				
			||||||
 | 
						PasswordComplexity                 []string
 | 
				
			||||||
 | 
						PasswordHashAlgo                   string
 | 
				
			||||||
 | 
						PasswordCheckPwn                   bool
 | 
				
			||||||
 | 
						SuccessfulTokensCacheSize          int
 | 
				
			||||||
 | 
						CSRFCookieName                     = "_csrf"
 | 
				
			||||||
 | 
						CSRFCookieHTTPOnly                 = 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()
 | 
				
			||||||
 | 
						verbatim := sec.Key(verbatimKey).String()
 | 
				
			||||||
 | 
						if uri != "" && verbatim != "" {
 | 
				
			||||||
 | 
							log.Fatal("Cannot specify both %s and %s", uriKey, verbatimKey)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// if we have no URI, use verbatim
 | 
				
			||||||
 | 
						if uri == "" {
 | 
				
			||||||
 | 
							return verbatim
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tempURI, err := url.Parse(uri)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Fatal("Failed to parse %s (%s): %v", uriKey, uri, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						switch tempURI.Scheme {
 | 
				
			||||||
 | 
						case "file":
 | 
				
			||||||
 | 
							buf, err := os.ReadFile(tempURI.RequestURI())
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								log.Fatal("Failed to read %s (%s): %v", uriKey, tempURI.RequestURI(), err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							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:
 | 
				
			||||||
 | 
							log.Fatal("Unsupported URI-Scheme %q (INTERNAL_TOKEN_URI = %q)", tempURI.Scheme, uri)
 | 
				
			||||||
 | 
							return ""
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// generateSaveInternalToken generates and saves the internal token to app.ini
 | 
				
			||||||
 | 
					func generateSaveInternalToken() {
 | 
				
			||||||
 | 
						token, err := generate.NewInternalToken()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Fatal("Error generate internal token: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InternalToken = token
 | 
				
			||||||
 | 
						CreateOrAppendToCustomConf("security.INTERNAL_TOKEN", func(cfg *ini.File) {
 | 
				
			||||||
 | 
							cfg.Section("security").Key("INTERNAL_TOKEN").SetValue(token)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func loadSecurityFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
 | 
						sec := rootCfg.Section("security")
 | 
				
			||||||
 | 
						InstallLock = sec.Key("INSTALL_LOCK").MustBool(false)
 | 
				
			||||||
 | 
						LogInRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt(7)
 | 
				
			||||||
 | 
						CookieUserName = sec.Key("COOKIE_USERNAME").MustString("gitea_awesome")
 | 
				
			||||||
 | 
						SecretKey = loadSecret(sec, "SECRET_KEY_URI", "SECRET_KEY")
 | 
				
			||||||
 | 
						if SecretKey == "" {
 | 
				
			||||||
 | 
							// FIXME: https://github.com/go-gitea/gitea/issues/16832
 | 
				
			||||||
 | 
							// Until it supports rotating an existing secret key, we shouldn't move users off of the widely used default value
 | 
				
			||||||
 | 
							SecretKey = "!#@FDEWREWR&*(" //nolint:gosec
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").MustString("gitea_incredible")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ReverseProxyAuthUser = sec.Key("REVERSE_PROXY_AUTHENTICATION_USER").MustString("X-WEBAUTH-USER")
 | 
				
			||||||
 | 
						ReverseProxyAuthEmail = sec.Key("REVERSE_PROXY_AUTHENTICATION_EMAIL").MustString("X-WEBAUTH-EMAIL")
 | 
				
			||||||
 | 
						ReverseProxyAuthFullName = sec.Key("REVERSE_PROXY_AUTHENTICATION_FULL_NAME").MustString("X-WEBAUTH-FULLNAME")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ReverseProxyLimit = sec.Key("REVERSE_PROXY_LIMIT").MustInt(1)
 | 
				
			||||||
 | 
						ReverseProxyTrustedProxies = sec.Key("REVERSE_PROXY_TRUSTED_PROXIES").Strings(",")
 | 
				
			||||||
 | 
						if len(ReverseProxyTrustedProxies) == 0 {
 | 
				
			||||||
 | 
							ReverseProxyTrustedProxies = []string{"127.0.0.0/8", "::1/128"}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						MinPasswordLength = sec.Key("MIN_PASSWORD_LENGTH").MustInt(6)
 | 
				
			||||||
 | 
						ImportLocalPaths = sec.Key("IMPORT_LOCAL_PATHS").MustBool(false)
 | 
				
			||||||
 | 
						DisableGitHooks = sec.Key("DISABLE_GIT_HOOKS").MustBool(true)
 | 
				
			||||||
 | 
						DisableWebhooks = sec.Key("DISABLE_WEBHOOKS").MustBool(false)
 | 
				
			||||||
 | 
						OnlyAllowPushIfGiteaEnvironmentSet = sec.Key("ONLY_ALLOW_PUSH_IF_GITEA_ENVIRONMENT_SET").MustBool(true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Ensure that the provided default hash algorithm is a valid hash algorithm
 | 
				
			||||||
 | 
						var algorithm *hash.PasswordHashAlgorithm
 | 
				
			||||||
 | 
						PasswordHashAlgo, algorithm = hash.SetDefaultPasswordHashAlgorithm(sec.Key("PASSWORD_HASH_ALGO").MustString(""))
 | 
				
			||||||
 | 
						if algorithm == nil {
 | 
				
			||||||
 | 
							log.Fatal("The provided password hash algorithm was invalid: %s", sec.Key("PASSWORD_HASH_ALGO").MustString(""))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						CSRFCookieHTTPOnly = sec.Key("CSRF_COOKIE_HTTP_ONLY").MustBool(true)
 | 
				
			||||||
 | 
						PasswordCheckPwn = sec.Key("PASSWORD_CHECK_PWN").MustBool(false)
 | 
				
			||||||
 | 
						SuccessfulTokensCacheSize = sec.Key("SUCCESSFUL_TOKENS_CACHE_SIZE").MustInt(20)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InternalToken = loadSecret(sec, "INTERNAL_TOKEN_URI", "INTERNAL_TOKEN")
 | 
				
			||||||
 | 
						if InstallLock && InternalToken == "" {
 | 
				
			||||||
 | 
							// if Gitea has been installed but the InternalToken hasn't been generated (upgrade from an old release), we should generate
 | 
				
			||||||
 | 
							// some users do cluster deployment, they still depend on this auto-generating behavior.
 | 
				
			||||||
 | 
							generateSaveInternalToken()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cfgdata := sec.Key("PASSWORD_COMPLEXITY").Strings(",")
 | 
				
			||||||
 | 
						if len(cfgdata) == 0 {
 | 
				
			||||||
 | 
							cfgdata = []string{"off"}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						PasswordComplexity = make([]string, 0, len(cfgdata))
 | 
				
			||||||
 | 
						for _, name := range cfgdata {
 | 
				
			||||||
 | 
							name := strings.ToLower(strings.Trim(name, `"`))
 | 
				
			||||||
 | 
							if name != "" {
 | 
				
			||||||
 | 
								PasswordComplexity = append(PasswordComplexity, name)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										356
									
								
								modules/setting/server.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										356
									
								
								modules/setting/server.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,356 @@
 | 
				
			|||||||
 | 
					// Copyright 2023 The Gitea Authors. All rights reserved.
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: MIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package setting
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/base64"
 | 
				
			||||||
 | 
						"net"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
 | 
						"path"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/json"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/util"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Scheme describes protocol types
 | 
				
			||||||
 | 
					type Scheme string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// enumerates all the scheme types
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						HTTP     Scheme = "http"
 | 
				
			||||||
 | 
						HTTPS    Scheme = "https"
 | 
				
			||||||
 | 
						FCGI     Scheme = "fcgi"
 | 
				
			||||||
 | 
						FCGIUnix Scheme = "fcgi+unix"
 | 
				
			||||||
 | 
						HTTPUnix Scheme = "http+unix"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// LandingPage describes the default page
 | 
				
			||||||
 | 
					type LandingPage string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// enumerates all the landing page types
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						LandingPageHome          LandingPage = "/"
 | 
				
			||||||
 | 
						LandingPageExplore       LandingPage = "/explore"
 | 
				
			||||||
 | 
						LandingPageOrganizations LandingPage = "/explore/organizations"
 | 
				
			||||||
 | 
						LandingPageLogin         LandingPage = "/user/login"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						// AppName is the Application name, used in the page title.
 | 
				
			||||||
 | 
						// It maps to ini:"APP_NAME"
 | 
				
			||||||
 | 
						AppName string
 | 
				
			||||||
 | 
						// AppURL is the Application ROOT_URL. It always has a '/' suffix
 | 
				
			||||||
 | 
						// It maps to ini:"ROOT_URL"
 | 
				
			||||||
 | 
						AppURL string
 | 
				
			||||||
 | 
						// AppSubURL represents the sub-url mounting point for gitea. It is either "" or starts with '/' and ends without '/', such as '/{subpath}'.
 | 
				
			||||||
 | 
						// This value is empty if site does not have sub-url.
 | 
				
			||||||
 | 
						AppSubURL string
 | 
				
			||||||
 | 
						// AppDataPath is the default path for storing data.
 | 
				
			||||||
 | 
						// It maps to ini:"APP_DATA_PATH" in [server] and defaults to AppWorkPath + "/data"
 | 
				
			||||||
 | 
						AppDataPath string
 | 
				
			||||||
 | 
						// LocalURL is the url for locally running applications to contact Gitea. It always has a '/' suffix
 | 
				
			||||||
 | 
						// It maps to ini:"LOCAL_ROOT_URL" in [server]
 | 
				
			||||||
 | 
						LocalURL string
 | 
				
			||||||
 | 
						// AssetVersion holds a opaque value that is used for cache-busting assets
 | 
				
			||||||
 | 
						AssetVersion string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Server settings
 | 
				
			||||||
 | 
						Protocol                   Scheme
 | 
				
			||||||
 | 
						UseProxyProtocol           bool // `ini:"USE_PROXY_PROTOCOL"`
 | 
				
			||||||
 | 
						ProxyProtocolTLSBridging   bool //`ini:"PROXY_PROTOCOL_TLS_BRIDGING"`
 | 
				
			||||||
 | 
						ProxyProtocolHeaderTimeout time.Duration
 | 
				
			||||||
 | 
						ProxyProtocolAcceptUnknown bool
 | 
				
			||||||
 | 
						Domain                     string
 | 
				
			||||||
 | 
						HTTPAddr                   string
 | 
				
			||||||
 | 
						HTTPPort                   string
 | 
				
			||||||
 | 
						LocalUseProxyProtocol      bool
 | 
				
			||||||
 | 
						RedirectOtherPort          bool
 | 
				
			||||||
 | 
						RedirectorUseProxyProtocol bool
 | 
				
			||||||
 | 
						PortToRedirect             string
 | 
				
			||||||
 | 
						OfflineMode                bool
 | 
				
			||||||
 | 
						CertFile                   string
 | 
				
			||||||
 | 
						KeyFile                    string
 | 
				
			||||||
 | 
						StaticRootPath             string
 | 
				
			||||||
 | 
						StaticCacheTime            time.Duration
 | 
				
			||||||
 | 
						EnableGzip                 bool
 | 
				
			||||||
 | 
						LandingPageURL             LandingPage
 | 
				
			||||||
 | 
						LandingPageCustom          string
 | 
				
			||||||
 | 
						UnixSocketPermission       uint32
 | 
				
			||||||
 | 
						EnablePprof                bool
 | 
				
			||||||
 | 
						PprofDataPath              string
 | 
				
			||||||
 | 
						EnableAcme                 bool
 | 
				
			||||||
 | 
						AcmeTOS                    bool
 | 
				
			||||||
 | 
						AcmeLiveDirectory          string
 | 
				
			||||||
 | 
						AcmeEmail                  string
 | 
				
			||||||
 | 
						AcmeURL                    string
 | 
				
			||||||
 | 
						AcmeCARoot                 string
 | 
				
			||||||
 | 
						SSLMinimumVersion          string
 | 
				
			||||||
 | 
						SSLMaximumVersion          string
 | 
				
			||||||
 | 
						SSLCurvePreferences        []string
 | 
				
			||||||
 | 
						SSLCipherSuites            []string
 | 
				
			||||||
 | 
						GracefulRestartable        bool
 | 
				
			||||||
 | 
						GracefulHammerTime         time.Duration
 | 
				
			||||||
 | 
						StartupTimeout             time.Duration
 | 
				
			||||||
 | 
						PerWriteTimeout            = 30 * time.Second
 | 
				
			||||||
 | 
						PerWritePerKbTimeout       = 10 * time.Second
 | 
				
			||||||
 | 
						StaticURLPrefix            string
 | 
				
			||||||
 | 
						AbsoluteAssetURL           string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						HasRobotsTxt bool
 | 
				
			||||||
 | 
						ManifestData string
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// MakeManifestData generates web app manifest JSON
 | 
				
			||||||
 | 
					func MakeManifestData(appName, appURL, absoluteAssetURL string) []byte {
 | 
				
			||||||
 | 
						type manifestIcon struct {
 | 
				
			||||||
 | 
							Src   string `json:"src"`
 | 
				
			||||||
 | 
							Type  string `json:"type"`
 | 
				
			||||||
 | 
							Sizes string `json:"sizes"`
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						type manifestJSON struct {
 | 
				
			||||||
 | 
							Name      string         `json:"name"`
 | 
				
			||||||
 | 
							ShortName string         `json:"short_name"`
 | 
				
			||||||
 | 
							StartURL  string         `json:"start_url"`
 | 
				
			||||||
 | 
							Icons     []manifestIcon `json:"icons"`
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bytes, err := json.Marshal(&manifestJSON{
 | 
				
			||||||
 | 
							Name:      appName,
 | 
				
			||||||
 | 
							ShortName: appName,
 | 
				
			||||||
 | 
							StartURL:  appURL,
 | 
				
			||||||
 | 
							Icons: []manifestIcon{
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									Src:   absoluteAssetURL + "/assets/img/logo.png",
 | 
				
			||||||
 | 
									Type:  "image/png",
 | 
				
			||||||
 | 
									Sizes: "512x512",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									Src:   absoluteAssetURL + "/assets/img/logo.svg",
 | 
				
			||||||
 | 
									Type:  "image/svg+xml",
 | 
				
			||||||
 | 
									Sizes: "512x512",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Error("unable to marshal manifest JSON. Error: %v", err)
 | 
				
			||||||
 | 
							return make([]byte, 0)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return bytes
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// MakeAbsoluteAssetURL returns the absolute asset url prefix without a trailing slash
 | 
				
			||||||
 | 
					func MakeAbsoluteAssetURL(appURL, staticURLPrefix string) string {
 | 
				
			||||||
 | 
						parsedPrefix, err := url.Parse(strings.TrimSuffix(staticURLPrefix, "/"))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Fatal("Unable to parse STATIC_URL_PREFIX: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err == nil && parsedPrefix.Hostname() == "" {
 | 
				
			||||||
 | 
							if staticURLPrefix == "" {
 | 
				
			||||||
 | 
								return strings.TrimSuffix(appURL, "/")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// StaticURLPrefix is just a path
 | 
				
			||||||
 | 
							return util.URLJoin(appURL, strings.TrimSuffix(staticURLPrefix, "/"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return strings.TrimSuffix(staticURLPrefix, "/")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func loadServerFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
 | 
						sec := rootCfg.Section("server")
 | 
				
			||||||
 | 
						AppName = rootCfg.Section("").Key("APP_NAME").MustString("Gitea: Git with a cup of tea")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Domain = sec.Key("DOMAIN").MustString("localhost")
 | 
				
			||||||
 | 
						HTTPAddr = sec.Key("HTTP_ADDR").MustString("0.0.0.0")
 | 
				
			||||||
 | 
						HTTPPort = sec.Key("HTTP_PORT").MustString("3000")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Protocol = HTTP
 | 
				
			||||||
 | 
						protocolCfg := sec.Key("PROTOCOL").String()
 | 
				
			||||||
 | 
						switch protocolCfg {
 | 
				
			||||||
 | 
						case "https":
 | 
				
			||||||
 | 
							Protocol = HTTPS
 | 
				
			||||||
 | 
							// FIXME: DEPRECATED to be removed in v1.18.0
 | 
				
			||||||
 | 
							if sec.HasKey("ENABLE_ACME") {
 | 
				
			||||||
 | 
								EnableAcme = sec.Key("ENABLE_ACME").MustBool(false)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								deprecatedSetting(rootCfg, "server", "ENABLE_LETSENCRYPT", "server", "ENABLE_ACME")
 | 
				
			||||||
 | 
								EnableAcme = sec.Key("ENABLE_LETSENCRYPT").MustBool(false)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if EnableAcme {
 | 
				
			||||||
 | 
								AcmeURL = sec.Key("ACME_URL").MustString("")
 | 
				
			||||||
 | 
								AcmeCARoot = sec.Key("ACME_CA_ROOT").MustString("")
 | 
				
			||||||
 | 
								// FIXME: DEPRECATED to be removed in v1.18.0
 | 
				
			||||||
 | 
								if sec.HasKey("ACME_ACCEPTTOS") {
 | 
				
			||||||
 | 
									AcmeTOS = sec.Key("ACME_ACCEPTTOS").MustBool(false)
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									deprecatedSetting(rootCfg, "server", "LETSENCRYPT_ACCEPTTOS", "server", "ACME_ACCEPTTOS")
 | 
				
			||||||
 | 
									AcmeTOS = sec.Key("LETSENCRYPT_ACCEPTTOS").MustBool(false)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if !AcmeTOS {
 | 
				
			||||||
 | 
									log.Fatal("ACME TOS is not accepted (ACME_ACCEPTTOS).")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// FIXME: DEPRECATED to be removed in v1.18.0
 | 
				
			||||||
 | 
								if sec.HasKey("ACME_DIRECTORY") {
 | 
				
			||||||
 | 
									AcmeLiveDirectory = sec.Key("ACME_DIRECTORY").MustString("https")
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									deprecatedSetting(rootCfg, "server", "LETSENCRYPT_DIRECTORY", "server", "ACME_DIRECTORY")
 | 
				
			||||||
 | 
									AcmeLiveDirectory = sec.Key("LETSENCRYPT_DIRECTORY").MustString("https")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// FIXME: DEPRECATED to be removed in v1.18.0
 | 
				
			||||||
 | 
								if sec.HasKey("ACME_EMAIL") {
 | 
				
			||||||
 | 
									AcmeEmail = sec.Key("ACME_EMAIL").MustString("")
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									deprecatedSetting(rootCfg, "server", "LETSENCRYPT_EMAIL", "server", "ACME_EMAIL")
 | 
				
			||||||
 | 
									AcmeEmail = sec.Key("LETSENCRYPT_EMAIL").MustString("")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								CertFile = sec.Key("CERT_FILE").String()
 | 
				
			||||||
 | 
								KeyFile = sec.Key("KEY_FILE").String()
 | 
				
			||||||
 | 
								if len(CertFile) > 0 && !filepath.IsAbs(CertFile) {
 | 
				
			||||||
 | 
									CertFile = filepath.Join(CustomPath, CertFile)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if len(KeyFile) > 0 && !filepath.IsAbs(KeyFile) {
 | 
				
			||||||
 | 
									KeyFile = filepath.Join(CustomPath, KeyFile)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							SSLMinimumVersion = sec.Key("SSL_MIN_VERSION").MustString("")
 | 
				
			||||||
 | 
							SSLMaximumVersion = sec.Key("SSL_MAX_VERSION").MustString("")
 | 
				
			||||||
 | 
							SSLCurvePreferences = sec.Key("SSL_CURVE_PREFERENCES").Strings(",")
 | 
				
			||||||
 | 
							SSLCipherSuites = sec.Key("SSL_CIPHER_SUITES").Strings(",")
 | 
				
			||||||
 | 
						case "fcgi":
 | 
				
			||||||
 | 
							Protocol = FCGI
 | 
				
			||||||
 | 
						case "fcgi+unix", "unix", "http+unix":
 | 
				
			||||||
 | 
							switch protocolCfg {
 | 
				
			||||||
 | 
							case "fcgi+unix":
 | 
				
			||||||
 | 
								Protocol = FCGIUnix
 | 
				
			||||||
 | 
							case "unix":
 | 
				
			||||||
 | 
								log.Warn("unix PROTOCOL value is deprecated, please use http+unix")
 | 
				
			||||||
 | 
								fallthrough
 | 
				
			||||||
 | 
							case "http+unix":
 | 
				
			||||||
 | 
								Protocol = HTTPUnix
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							UnixSocketPermissionRaw := sec.Key("UNIX_SOCKET_PERMISSION").MustString("666")
 | 
				
			||||||
 | 
							UnixSocketPermissionParsed, err := strconv.ParseUint(UnixSocketPermissionRaw, 8, 32)
 | 
				
			||||||
 | 
							if err != nil || UnixSocketPermissionParsed > 0o777 {
 | 
				
			||||||
 | 
								log.Fatal("Failed to parse unixSocketPermission: %s", UnixSocketPermissionRaw)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							UnixSocketPermission = uint32(UnixSocketPermissionParsed)
 | 
				
			||||||
 | 
							if !filepath.IsAbs(HTTPAddr) {
 | 
				
			||||||
 | 
								HTTPAddr = filepath.Join(AppWorkPath, HTTPAddr)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						UseProxyProtocol = sec.Key("USE_PROXY_PROTOCOL").MustBool(false)
 | 
				
			||||||
 | 
						ProxyProtocolTLSBridging = sec.Key("PROXY_PROTOCOL_TLS_BRIDGING").MustBool(false)
 | 
				
			||||||
 | 
						ProxyProtocolHeaderTimeout = sec.Key("PROXY_PROTOCOL_HEADER_TIMEOUT").MustDuration(5 * time.Second)
 | 
				
			||||||
 | 
						ProxyProtocolAcceptUnknown = sec.Key("PROXY_PROTOCOL_ACCEPT_UNKNOWN").MustBool(false)
 | 
				
			||||||
 | 
						GracefulRestartable = sec.Key("ALLOW_GRACEFUL_RESTARTS").MustBool(true)
 | 
				
			||||||
 | 
						GracefulHammerTime = sec.Key("GRACEFUL_HAMMER_TIME").MustDuration(60 * time.Second)
 | 
				
			||||||
 | 
						StartupTimeout = sec.Key("STARTUP_TIMEOUT").MustDuration(0 * time.Second)
 | 
				
			||||||
 | 
						PerWriteTimeout = sec.Key("PER_WRITE_TIMEOUT").MustDuration(PerWriteTimeout)
 | 
				
			||||||
 | 
						PerWritePerKbTimeout = sec.Key("PER_WRITE_PER_KB_TIMEOUT").MustDuration(PerWritePerKbTimeout)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						defaultAppURL := string(Protocol) + "://" + Domain + ":" + HTTPPort
 | 
				
			||||||
 | 
						AppURL = sec.Key("ROOT_URL").MustString(defaultAppURL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Check validity of AppURL
 | 
				
			||||||
 | 
						appURL, err := url.Parse(AppURL)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Fatal("Invalid ROOT_URL '%s': %s", AppURL, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Remove default ports from AppURL.
 | 
				
			||||||
 | 
						// (scheme-based URL normalization, RFC 3986 section 6.2.3)
 | 
				
			||||||
 | 
						if (appURL.Scheme == string(HTTP) && appURL.Port() == "80") || (appURL.Scheme == string(HTTPS) && appURL.Port() == "443") {
 | 
				
			||||||
 | 
							appURL.Host = appURL.Hostname()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// This should be TrimRight to ensure that there is only a single '/' at the end of AppURL.
 | 
				
			||||||
 | 
						AppURL = strings.TrimRight(appURL.String(), "/") + "/"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Suburl should start with '/' and end without '/', such as '/{subpath}'.
 | 
				
			||||||
 | 
						// This value is empty if site does not have sub-url.
 | 
				
			||||||
 | 
						AppSubURL = strings.TrimSuffix(appURL.Path, "/")
 | 
				
			||||||
 | 
						StaticURLPrefix = strings.TrimSuffix(sec.Key("STATIC_URL_PREFIX").MustString(AppSubURL), "/")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Check if Domain differs from AppURL domain than update it to AppURL's domain
 | 
				
			||||||
 | 
						urlHostname := appURL.Hostname()
 | 
				
			||||||
 | 
						if urlHostname != Domain && net.ParseIP(urlHostname) == nil && urlHostname != "" {
 | 
				
			||||||
 | 
							Domain = urlHostname
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						AbsoluteAssetURL = MakeAbsoluteAssetURL(AppURL, StaticURLPrefix)
 | 
				
			||||||
 | 
						AssetVersion = strings.ReplaceAll(AppVer, "+", "~") // make sure the version string is clear (no real escaping is needed)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						manifestBytes := MakeManifestData(AppName, AppURL, AbsoluteAssetURL)
 | 
				
			||||||
 | 
						ManifestData = `application/json;base64,` + base64.StdEncoding.EncodeToString(manifestBytes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var defaultLocalURL string
 | 
				
			||||||
 | 
						switch Protocol {
 | 
				
			||||||
 | 
						case HTTPUnix:
 | 
				
			||||||
 | 
							defaultLocalURL = "http://unix/"
 | 
				
			||||||
 | 
						case FCGI:
 | 
				
			||||||
 | 
							defaultLocalURL = AppURL
 | 
				
			||||||
 | 
						case FCGIUnix:
 | 
				
			||||||
 | 
							defaultLocalURL = AppURL
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							defaultLocalURL = string(Protocol) + "://"
 | 
				
			||||||
 | 
							if HTTPAddr == "0.0.0.0" {
 | 
				
			||||||
 | 
								defaultLocalURL += net.JoinHostPort("localhost", HTTPPort) + "/"
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								defaultLocalURL += net.JoinHostPort(HTTPAddr, HTTPPort) + "/"
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						LocalURL = sec.Key("LOCAL_ROOT_URL").MustString(defaultLocalURL)
 | 
				
			||||||
 | 
						LocalURL = strings.TrimRight(LocalURL, "/") + "/"
 | 
				
			||||||
 | 
						LocalUseProxyProtocol = sec.Key("LOCAL_USE_PROXY_PROTOCOL").MustBool(UseProxyProtocol)
 | 
				
			||||||
 | 
						RedirectOtherPort = sec.Key("REDIRECT_OTHER_PORT").MustBool(false)
 | 
				
			||||||
 | 
						PortToRedirect = sec.Key("PORT_TO_REDIRECT").MustString("80")
 | 
				
			||||||
 | 
						RedirectorUseProxyProtocol = sec.Key("REDIRECTOR_USE_PROXY_PROTOCOL").MustBool(UseProxyProtocol)
 | 
				
			||||||
 | 
						OfflineMode = sec.Key("OFFLINE_MODE").MustBool()
 | 
				
			||||||
 | 
						Log.DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool()
 | 
				
			||||||
 | 
						if len(StaticRootPath) == 0 {
 | 
				
			||||||
 | 
							StaticRootPath = AppWorkPath
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						StaticRootPath = sec.Key("STATIC_ROOT_PATH").MustString(StaticRootPath)
 | 
				
			||||||
 | 
						StaticCacheTime = sec.Key("STATIC_CACHE_TIME").MustDuration(6 * time.Hour)
 | 
				
			||||||
 | 
						AppDataPath = sec.Key("APP_DATA_PATH").MustString(path.Join(AppWorkPath, "data"))
 | 
				
			||||||
 | 
						if !filepath.IsAbs(AppDataPath) {
 | 
				
			||||||
 | 
							log.Info("The provided APP_DATA_PATH: %s is not absolute - it will be made absolute against the work path: %s", AppDataPath, AppWorkPath)
 | 
				
			||||||
 | 
							AppDataPath = filepath.ToSlash(filepath.Join(AppWorkPath, AppDataPath))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EnableGzip = sec.Key("ENABLE_GZIP").MustBool()
 | 
				
			||||||
 | 
						EnablePprof = sec.Key("ENABLE_PPROF").MustBool(false)
 | 
				
			||||||
 | 
						PprofDataPath = sec.Key("PPROF_DATA_PATH").MustString(path.Join(AppWorkPath, "data/tmp/pprof"))
 | 
				
			||||||
 | 
						if !filepath.IsAbs(PprofDataPath) {
 | 
				
			||||||
 | 
							PprofDataPath = filepath.Join(AppWorkPath, PprofDataPath)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						landingPage := sec.Key("LANDING_PAGE").MustString("home")
 | 
				
			||||||
 | 
						switch landingPage {
 | 
				
			||||||
 | 
						case "explore":
 | 
				
			||||||
 | 
							LandingPageURL = LandingPageExplore
 | 
				
			||||||
 | 
						case "organizations":
 | 
				
			||||||
 | 
							LandingPageURL = LandingPageOrganizations
 | 
				
			||||||
 | 
						case "login":
 | 
				
			||||||
 | 
							LandingPageURL = LandingPageLogin
 | 
				
			||||||
 | 
						case "":
 | 
				
			||||||
 | 
						case "home":
 | 
				
			||||||
 | 
							LandingPageURL = LandingPageHome
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							LandingPageURL = LandingPage(landingPage)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						HasRobotsTxt, err = util.IsFile(path.Join(CustomPath, "robots.txt"))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Error("Unable to check if %s is a file. Error: %v", path.Join(CustomPath, "robots.txt"), err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -12,6 +12,15 @@ import (
 | 
				
			|||||||
	"code.gitea.io/gitea/modules/structs"
 | 
						"code.gitea.io/gitea/modules/structs"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// enumerates all the types of captchas
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						ImageCaptcha = "image"
 | 
				
			||||||
 | 
						ReCaptcha    = "recaptcha"
 | 
				
			||||||
 | 
						HCaptcha     = "hcaptcha"
 | 
				
			||||||
 | 
						MCaptcha     = "mcaptcha"
 | 
				
			||||||
 | 
						CfTurnstile  = "cfturnstile"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Service settings
 | 
					// Service settings
 | 
				
			||||||
var Service = struct {
 | 
					var Service = struct {
 | 
				
			||||||
	DefaultUserVisibility                   string
 | 
						DefaultUserVisibility                   string
 | 
				
			||||||
@@ -105,8 +114,8 @@ func (a AllowedVisibility) ToVisibleTypeSlice() (result []structs.VisibleType) {
 | 
				
			|||||||
	return result
 | 
						return result
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newService() {
 | 
					func loadServiceFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	sec := Cfg.Section("service")
 | 
						sec := rootCfg.Section("service")
 | 
				
			||||||
	Service.ActiveCodeLives = sec.Key("ACTIVE_CODE_LIVE_MINUTES").MustInt(180)
 | 
						Service.ActiveCodeLives = sec.Key("ACTIVE_CODE_LIVE_MINUTES").MustInt(180)
 | 
				
			||||||
	Service.ResetPwdCodeLives = sec.Key("RESET_PASSWD_CODE_LIVE_MINUTES").MustInt(180)
 | 
						Service.ResetPwdCodeLives = sec.Key("RESET_PASSWD_CODE_LIVE_MINUTES").MustInt(180)
 | 
				
			||||||
	Service.DisableRegistration = sec.Key("DISABLE_REGISTRATION").MustBool()
 | 
						Service.DisableRegistration = sec.Key("DISABLE_REGISTRATION").MustBool()
 | 
				
			||||||
@@ -184,11 +193,13 @@ func newService() {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	Service.ValidSiteURLSchemes = schemes
 | 
						Service.ValidSiteURLSchemes = schemes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := Cfg.Section("service.explore").MapTo(&Service.Explore); err != nil {
 | 
						mustMapSetting(rootCfg, "service.explore", &Service.Explore)
 | 
				
			||||||
		log.Fatal("Failed to map service.explore settings: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sec = Cfg.Section("openid")
 | 
						loadOpenIDSetting(rootCfg)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func loadOpenIDSetting(rootCfg ConfigProvider) {
 | 
				
			||||||
 | 
						sec := rootCfg.Section("openid")
 | 
				
			||||||
	Service.EnableOpenIDSignIn = sec.Key("ENABLE_OPENID_SIGNIN").MustBool(!InstallLock)
 | 
						Service.EnableOpenIDSignIn = sec.Key("ENABLE_OPENID_SIGNIN").MustBool(!InstallLock)
 | 
				
			||||||
	Service.EnableOpenIDSignUp = sec.Key("ENABLE_OPENID_SIGNUP").MustBool(!Service.DisableRegistration && Service.EnableOpenIDSignIn)
 | 
						Service.EnableOpenIDSignUp = sec.Key("ENABLE_OPENID_SIGNUP").MustBool(!Service.DisableRegistration && Service.EnableOpenIDSignIn)
 | 
				
			||||||
	pats := sec.Key("WHITELISTED_URIS").Strings(" ")
 | 
						pats := sec.Key("WHITELISTED_URIS").Strings(" ")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,8 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// SessionConfig defines Session settings
 | 
					// SessionConfig defines Session settings
 | 
				
			||||||
var SessionConfig = struct {
 | 
					var SessionConfig = struct {
 | 
				
			||||||
	Provider string
 | 
						OriginalProvider string
 | 
				
			||||||
 | 
						Provider         string
 | 
				
			||||||
	// Provider configuration, it's corresponding to provider.
 | 
						// Provider configuration, it's corresponding to provider.
 | 
				
			||||||
	ProviderConfig string
 | 
						ProviderConfig string
 | 
				
			||||||
	// Cookie name to save session ID. Default is "MacaronSession".
 | 
						// Cookie name to save session ID. Default is "MacaronSession".
 | 
				
			||||||
@@ -39,8 +40,8 @@ var SessionConfig = struct {
 | 
				
			|||||||
	SameSite:    http.SameSiteLaxMode,
 | 
						SameSite:    http.SameSiteLaxMode,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newSessionService() {
 | 
					func loadSessionFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	sec := Cfg.Section("session")
 | 
						sec := rootCfg.Section("session")
 | 
				
			||||||
	SessionConfig.Provider = sec.Key("PROVIDER").In("memory",
 | 
						SessionConfig.Provider = sec.Key("PROVIDER").In("memory",
 | 
				
			||||||
		[]string{"memory", "file", "redis", "mysql", "postgres", "couchbase", "memcache", "db"})
 | 
							[]string{"memory", "file", "redis", "mysql", "postgres", "couchbase", "memcache", "db"})
 | 
				
			||||||
	SessionConfig.ProviderConfig = strings.Trim(sec.Key("PROVIDER_CONFIG").MustString(path.Join(AppDataPath, "sessions")), "\" ")
 | 
						SessionConfig.ProviderConfig = strings.Trim(sec.Key("PROVIDER_CONFIG").MustString(path.Join(AppDataPath, "sessions")), "\" ")
 | 
				
			||||||
@@ -67,6 +68,7 @@ func newSessionService() {
 | 
				
			|||||||
		log.Fatal("Can't shadow session config: %v", err)
 | 
							log.Fatal("Can't shadow session config: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	SessionConfig.ProviderConfig = string(shadowConfig)
 | 
						SessionConfig.ProviderConfig = string(shadowConfig)
 | 
				
			||||||
 | 
						SessionConfig.OriginalProvider = SessionConfig.Provider
 | 
				
			||||||
	SessionConfig.Provider = "VirtualSession"
 | 
						SessionConfig.Provider = "VirtualSession"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log.Info("Session Service Enabled")
 | 
						log.Info("Session Service Enabled")
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										197
									
								
								modules/setting/ssh.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								modules/setting/ssh.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,197 @@
 | 
				
			|||||||
 | 
					// Copyright 2023 The Gitea Authors. All rights reserved.
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: MIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package setting
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"path"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"text/template"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/util"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gossh "golang.org/x/crypto/ssh"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var SSH = struct {
 | 
				
			||||||
 | 
						Disabled                              bool               `ini:"DISABLE_SSH"`
 | 
				
			||||||
 | 
						StartBuiltinServer                    bool               `ini:"START_SSH_SERVER"`
 | 
				
			||||||
 | 
						BuiltinServerUser                     string             `ini:"BUILTIN_SSH_SERVER_USER"`
 | 
				
			||||||
 | 
						UseProxyProtocol                      bool               `ini:"SSH_SERVER_USE_PROXY_PROTOCOL"`
 | 
				
			||||||
 | 
						Domain                                string             `ini:"SSH_DOMAIN"`
 | 
				
			||||||
 | 
						Port                                  int                `ini:"SSH_PORT"`
 | 
				
			||||||
 | 
						User                                  string             `ini:"SSH_USER"`
 | 
				
			||||||
 | 
						ListenHost                            string             `ini:"SSH_LISTEN_HOST"`
 | 
				
			||||||
 | 
						ListenPort                            int                `ini:"SSH_LISTEN_PORT"`
 | 
				
			||||||
 | 
						RootPath                              string             `ini:"SSH_ROOT_PATH"`
 | 
				
			||||||
 | 
						ServerCiphers                         []string           `ini:"SSH_SERVER_CIPHERS"`
 | 
				
			||||||
 | 
						ServerKeyExchanges                    []string           `ini:"SSH_SERVER_KEY_EXCHANGES"`
 | 
				
			||||||
 | 
						ServerMACs                            []string           `ini:"SSH_SERVER_MACS"`
 | 
				
			||||||
 | 
						ServerHostKeys                        []string           `ini:"SSH_SERVER_HOST_KEYS"`
 | 
				
			||||||
 | 
						KeyTestPath                           string             `ini:"SSH_KEY_TEST_PATH"`
 | 
				
			||||||
 | 
						KeygenPath                            string             `ini:"SSH_KEYGEN_PATH"`
 | 
				
			||||||
 | 
						AuthorizedKeysBackup                  bool               `ini:"SSH_AUTHORIZED_KEYS_BACKUP"`
 | 
				
			||||||
 | 
						AuthorizedPrincipalsBackup            bool               `ini:"SSH_AUTHORIZED_PRINCIPALS_BACKUP"`
 | 
				
			||||||
 | 
						AuthorizedKeysCommandTemplate         string             `ini:"SSH_AUTHORIZED_KEYS_COMMAND_TEMPLATE"`
 | 
				
			||||||
 | 
						AuthorizedKeysCommandTemplateTemplate *template.Template `ini:"-"`
 | 
				
			||||||
 | 
						MinimumKeySizeCheck                   bool               `ini:"-"`
 | 
				
			||||||
 | 
						MinimumKeySizes                       map[string]int     `ini:"-"`
 | 
				
			||||||
 | 
						CreateAuthorizedKeysFile              bool               `ini:"SSH_CREATE_AUTHORIZED_KEYS_FILE"`
 | 
				
			||||||
 | 
						CreateAuthorizedPrincipalsFile        bool               `ini:"SSH_CREATE_AUTHORIZED_PRINCIPALS_FILE"`
 | 
				
			||||||
 | 
						ExposeAnonymous                       bool               `ini:"SSH_EXPOSE_ANONYMOUS"`
 | 
				
			||||||
 | 
						AuthorizedPrincipalsAllow             []string           `ini:"SSH_AUTHORIZED_PRINCIPALS_ALLOW"`
 | 
				
			||||||
 | 
						AuthorizedPrincipalsEnabled           bool               `ini:"-"`
 | 
				
			||||||
 | 
						TrustedUserCAKeys                     []string           `ini:"SSH_TRUSTED_USER_CA_KEYS"`
 | 
				
			||||||
 | 
						TrustedUserCAKeysFile                 string             `ini:"SSH_TRUSTED_USER_CA_KEYS_FILENAME"`
 | 
				
			||||||
 | 
						TrustedUserCAKeysParsed               []gossh.PublicKey  `ini:"-"`
 | 
				
			||||||
 | 
						PerWriteTimeout                       time.Duration      `ini:"SSH_PER_WRITE_TIMEOUT"`
 | 
				
			||||||
 | 
						PerWritePerKbTimeout                  time.Duration      `ini:"SSH_PER_WRITE_PER_KB_TIMEOUT"`
 | 
				
			||||||
 | 
					}{
 | 
				
			||||||
 | 
						Disabled:                      false,
 | 
				
			||||||
 | 
						StartBuiltinServer:            false,
 | 
				
			||||||
 | 
						Domain:                        "",
 | 
				
			||||||
 | 
						Port:                          22,
 | 
				
			||||||
 | 
						ServerCiphers:                 []string{"chacha20-poly1305@openssh.com", "aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", "aes256-gcm@openssh.com"},
 | 
				
			||||||
 | 
						ServerKeyExchanges:            []string{"curve25519-sha256", "ecdh-sha2-nistp256", "ecdh-sha2-nistp384", "ecdh-sha2-nistp521", "diffie-hellman-group14-sha256", "diffie-hellman-group14-sha1"},
 | 
				
			||||||
 | 
						ServerMACs:                    []string{"hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha1"},
 | 
				
			||||||
 | 
						KeygenPath:                    "ssh-keygen",
 | 
				
			||||||
 | 
						MinimumKeySizeCheck:           true,
 | 
				
			||||||
 | 
						MinimumKeySizes:               map[string]int{"ed25519": 256, "ed25519-sk": 256, "ecdsa": 256, "ecdsa-sk": 256, "rsa": 2047},
 | 
				
			||||||
 | 
						ServerHostKeys:                []string{"ssh/gitea.rsa", "ssh/gogs.rsa"},
 | 
				
			||||||
 | 
						AuthorizedKeysCommandTemplate: "{{.AppPath}} --config={{.CustomConf}} serv key-{{.Key.ID}}",
 | 
				
			||||||
 | 
						PerWriteTimeout:               PerWriteTimeout,
 | 
				
			||||||
 | 
						PerWritePerKbTimeout:          PerWritePerKbTimeout,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func parseAuthorizedPrincipalsAllow(values []string) ([]string, bool) {
 | 
				
			||||||
 | 
						anything := false
 | 
				
			||||||
 | 
						email := false
 | 
				
			||||||
 | 
						username := false
 | 
				
			||||||
 | 
						for _, value := range values {
 | 
				
			||||||
 | 
							v := strings.ToLower(strings.TrimSpace(value))
 | 
				
			||||||
 | 
							switch v {
 | 
				
			||||||
 | 
							case "off":
 | 
				
			||||||
 | 
								return []string{"off"}, false
 | 
				
			||||||
 | 
							case "email":
 | 
				
			||||||
 | 
								email = true
 | 
				
			||||||
 | 
							case "username":
 | 
				
			||||||
 | 
								username = true
 | 
				
			||||||
 | 
							case "anything":
 | 
				
			||||||
 | 
								anything = true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if anything {
 | 
				
			||||||
 | 
							return []string{"anything"}, true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						authorizedPrincipalsAllow := []string{}
 | 
				
			||||||
 | 
						if username {
 | 
				
			||||||
 | 
							authorizedPrincipalsAllow = append(authorizedPrincipalsAllow, "username")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if email {
 | 
				
			||||||
 | 
							authorizedPrincipalsAllow = append(authorizedPrincipalsAllow, "email")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return authorizedPrincipalsAllow, true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func loadSSHFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
 | 
						sec := rootCfg.Section("server")
 | 
				
			||||||
 | 
						if len(SSH.Domain) == 0 {
 | 
				
			||||||
 | 
							SSH.Domain = Domain
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						homeDir, err := util.HomeDir()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Fatal("Failed to get home directory: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						homeDir = strings.ReplaceAll(homeDir, "\\", "/")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SSH.RootPath = path.Join(homeDir, ".ssh")
 | 
				
			||||||
 | 
						serverCiphers := sec.Key("SSH_SERVER_CIPHERS").Strings(",")
 | 
				
			||||||
 | 
						if len(serverCiphers) > 0 {
 | 
				
			||||||
 | 
							SSH.ServerCiphers = serverCiphers
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						serverKeyExchanges := sec.Key("SSH_SERVER_KEY_EXCHANGES").Strings(",")
 | 
				
			||||||
 | 
						if len(serverKeyExchanges) > 0 {
 | 
				
			||||||
 | 
							SSH.ServerKeyExchanges = serverKeyExchanges
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						serverMACs := sec.Key("SSH_SERVER_MACS").Strings(",")
 | 
				
			||||||
 | 
						if len(serverMACs) > 0 {
 | 
				
			||||||
 | 
							SSH.ServerMACs = serverMACs
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						SSH.KeyTestPath = os.TempDir()
 | 
				
			||||||
 | 
						if err = sec.MapTo(&SSH); err != nil {
 | 
				
			||||||
 | 
							log.Fatal("Failed to map SSH settings: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for i, key := range SSH.ServerHostKeys {
 | 
				
			||||||
 | 
							if !filepath.IsAbs(key) {
 | 
				
			||||||
 | 
								SSH.ServerHostKeys[i] = filepath.Join(AppDataPath, key)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SSH.KeygenPath = sec.Key("SSH_KEYGEN_PATH").MustString("ssh-keygen")
 | 
				
			||||||
 | 
						SSH.Port = sec.Key("SSH_PORT").MustInt(22)
 | 
				
			||||||
 | 
						SSH.ListenPort = sec.Key("SSH_LISTEN_PORT").MustInt(SSH.Port)
 | 
				
			||||||
 | 
						SSH.UseProxyProtocol = sec.Key("SSH_SERVER_USE_PROXY_PROTOCOL").MustBool(false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// When disable SSH, start builtin server value is ignored.
 | 
				
			||||||
 | 
						if SSH.Disabled {
 | 
				
			||||||
 | 
							SSH.StartBuiltinServer = false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SSH.TrustedUserCAKeysFile = sec.Key("SSH_TRUSTED_USER_CA_KEYS_FILENAME").MustString(filepath.Join(SSH.RootPath, "gitea-trusted-user-ca-keys.pem"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, caKey := range SSH.TrustedUserCAKeys {
 | 
				
			||||||
 | 
							pubKey, _, _, _, err := gossh.ParseAuthorizedKey([]byte(caKey))
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								log.Fatal("Failed to parse TrustedUserCaKeys: %s %v", caKey, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							SSH.TrustedUserCAKeysParsed = append(SSH.TrustedUserCAKeysParsed, pubKey)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(SSH.TrustedUserCAKeys) > 0 {
 | 
				
			||||||
 | 
							// Set the default as email,username otherwise we can leave it empty
 | 
				
			||||||
 | 
							sec.Key("SSH_AUTHORIZED_PRINCIPALS_ALLOW").MustString("username,email")
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							sec.Key("SSH_AUTHORIZED_PRINCIPALS_ALLOW").MustString("off")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SSH.AuthorizedPrincipalsAllow, SSH.AuthorizedPrincipalsEnabled = parseAuthorizedPrincipalsAllow(sec.Key("SSH_AUTHORIZED_PRINCIPALS_ALLOW").Strings(","))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SSH.MinimumKeySizeCheck = sec.Key("MINIMUM_KEY_SIZE_CHECK").MustBool(SSH.MinimumKeySizeCheck)
 | 
				
			||||||
 | 
						minimumKeySizes := rootCfg.Section("ssh.minimum_key_sizes").Keys()
 | 
				
			||||||
 | 
						for _, key := range minimumKeySizes {
 | 
				
			||||||
 | 
							if key.MustInt() != -1 {
 | 
				
			||||||
 | 
								SSH.MinimumKeySizes[strings.ToLower(key.Name())] = key.MustInt()
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								delete(SSH.MinimumKeySizes, strings.ToLower(key.Name()))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SSH.AuthorizedKeysBackup = sec.Key("SSH_AUTHORIZED_KEYS_BACKUP").MustBool(true)
 | 
				
			||||||
 | 
						SSH.CreateAuthorizedKeysFile = sec.Key("SSH_CREATE_AUTHORIZED_KEYS_FILE").MustBool(true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SSH.AuthorizedPrincipalsBackup = false
 | 
				
			||||||
 | 
						SSH.CreateAuthorizedPrincipalsFile = false
 | 
				
			||||||
 | 
						if SSH.AuthorizedPrincipalsEnabled {
 | 
				
			||||||
 | 
							SSH.AuthorizedPrincipalsBackup = sec.Key("SSH_AUTHORIZED_PRINCIPALS_BACKUP").MustBool(true)
 | 
				
			||||||
 | 
							SSH.CreateAuthorizedPrincipalsFile = sec.Key("SSH_CREATE_AUTHORIZED_PRINCIPALS_FILE").MustBool(true)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SSH.ExposeAnonymous = sec.Key("SSH_EXPOSE_ANONYMOUS").MustBool(false)
 | 
				
			||||||
 | 
						SSH.AuthorizedKeysCommandTemplate = sec.Key("SSH_AUTHORIZED_KEYS_COMMAND_TEMPLATE").MustString(SSH.AuthorizedKeysCommandTemplate)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SSH.AuthorizedKeysCommandTemplateTemplate = template.Must(template.New("").Parse(SSH.AuthorizedKeysCommandTemplate))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SSH.PerWriteTimeout = sec.Key("SSH_PER_WRITE_TIMEOUT").MustDuration(PerWriteTimeout)
 | 
				
			||||||
 | 
						SSH.PerWritePerKbTimeout = sec.Key("SSH_PER_WRITE_PER_KB_TIMEOUT").MustDuration(PerWritePerKbTimeout)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ensure parseRunModeSetting has been executed before this
 | 
				
			||||||
 | 
						SSH.BuiltinServerUser = rootCfg.Section("server").Key("BUILTIN_SSH_SERVER_USER").MustString(RunUser)
 | 
				
			||||||
 | 
						SSH.User = rootCfg.Section("server").Key("SSH_USER").MustString(SSH.BuiltinServerUser)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -30,9 +30,9 @@ func (s *Storage) MapTo(v interface{}) error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getStorage(name, typ string, targetSec *ini.Section) Storage {
 | 
					func getStorage(rootCfg ConfigProvider, name, typ string, targetSec *ini.Section) Storage {
 | 
				
			||||||
	const sectionName = "storage"
 | 
						const sectionName = "storage"
 | 
				
			||||||
	sec := Cfg.Section(sectionName)
 | 
						sec := rootCfg.Section(sectionName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Global Defaults
 | 
						// Global Defaults
 | 
				
			||||||
	sec.Key("MINIO_ENDPOINT").MustString("localhost:9000")
 | 
						sec.Key("MINIO_ENDPOINT").MustString("localhost:9000")
 | 
				
			||||||
@@ -43,7 +43,7 @@ func getStorage(name, typ string, targetSec *ini.Section) Storage {
 | 
				
			|||||||
	sec.Key("MINIO_USE_SSL").MustBool(false)
 | 
						sec.Key("MINIO_USE_SSL").MustBool(false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if targetSec == nil {
 | 
						if targetSec == nil {
 | 
				
			||||||
		targetSec, _ = Cfg.NewSection(name)
 | 
							targetSec, _ = rootCfg.NewSection(name)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var storage Storage
 | 
						var storage Storage
 | 
				
			||||||
@@ -51,12 +51,12 @@ func getStorage(name, typ string, targetSec *ini.Section) Storage {
 | 
				
			|||||||
	storage.Type = typ
 | 
						storage.Type = typ
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	overrides := make([]*ini.Section, 0, 3)
 | 
						overrides := make([]*ini.Section, 0, 3)
 | 
				
			||||||
	nameSec, err := Cfg.GetSection(sectionName + "." + name)
 | 
						nameSec, err := rootCfg.GetSection(sectionName + "." + name)
 | 
				
			||||||
	if err == nil {
 | 
						if err == nil {
 | 
				
			||||||
		overrides = append(overrides, nameSec)
 | 
							overrides = append(overrides, nameSec)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	typeSec, err := Cfg.GetSection(sectionName + "." + typ)
 | 
						typeSec, err := rootCfg.GetSection(sectionName + "." + typ)
 | 
				
			||||||
	if err == nil {
 | 
						if err == nil {
 | 
				
			||||||
		overrides = append(overrides, typeSec)
 | 
							overrides = append(overrides, typeSec)
 | 
				
			||||||
		nextType := typeSec.Key("STORAGE_TYPE").String()
 | 
							nextType := typeSec.Key("STORAGE_TYPE").String()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,11 +20,12 @@ MINIO_BUCKET = gitea-attachment
 | 
				
			|||||||
STORAGE_TYPE = minio
 | 
					STORAGE_TYPE = minio
 | 
				
			||||||
MINIO_ENDPOINT = my_minio:9000
 | 
					MINIO_ENDPOINT = my_minio:9000
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
	Cfg, _ = ini.Load([]byte(iniStr))
 | 
						cfg, err := ini.Load([]byte(iniStr))
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sec := Cfg.Section("attachment")
 | 
						sec := cfg.Section("attachment")
 | 
				
			||||||
	storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
						storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
				
			||||||
	storage := getStorage("attachments", storageType, sec)
 | 
						storage := getStorage(cfg, "attachments", storageType, sec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.EqualValues(t, "minio", storage.Type)
 | 
						assert.EqualValues(t, "minio", storage.Type)
 | 
				
			||||||
	assert.EqualValues(t, "my_minio:9000", storage.Section.Key("MINIO_ENDPOINT").String())
 | 
						assert.EqualValues(t, "my_minio:9000", storage.Section.Key("MINIO_ENDPOINT").String())
 | 
				
			||||||
@@ -42,11 +43,12 @@ MINIO_BUCKET = gitea-attachment
 | 
				
			|||||||
[storage.minio]
 | 
					[storage.minio]
 | 
				
			||||||
MINIO_BUCKET = gitea
 | 
					MINIO_BUCKET = gitea
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
	Cfg, _ = ini.Load([]byte(iniStr))
 | 
						cfg, err := ini.Load([]byte(iniStr))
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sec := Cfg.Section("attachment")
 | 
						sec := cfg.Section("attachment")
 | 
				
			||||||
	storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
						storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
				
			||||||
	storage := getStorage("attachments", storageType, sec)
 | 
						storage := getStorage(cfg, "attachments", storageType, sec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.EqualValues(t, "minio", storage.Type)
 | 
						assert.EqualValues(t, "minio", storage.Type)
 | 
				
			||||||
	assert.EqualValues(t, "gitea-attachment", storage.Section.Key("MINIO_BUCKET").String())
 | 
						assert.EqualValues(t, "gitea-attachment", storage.Section.Key("MINIO_BUCKET").String())
 | 
				
			||||||
@@ -63,11 +65,12 @@ MINIO_BUCKET = gitea-minio
 | 
				
			|||||||
[storage]
 | 
					[storage]
 | 
				
			||||||
MINIO_BUCKET = gitea
 | 
					MINIO_BUCKET = gitea
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
	Cfg, _ = ini.Load([]byte(iniStr))
 | 
						cfg, err := ini.Load([]byte(iniStr))
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sec := Cfg.Section("attachment")
 | 
						sec := cfg.Section("attachment")
 | 
				
			||||||
	storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
						storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
				
			||||||
	storage := getStorage("attachments", storageType, sec)
 | 
						storage := getStorage(cfg, "attachments", storageType, sec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.EqualValues(t, "minio", storage.Type)
 | 
						assert.EqualValues(t, "minio", storage.Type)
 | 
				
			||||||
	assert.EqualValues(t, "gitea-minio", storage.Section.Key("MINIO_BUCKET").String())
 | 
						assert.EqualValues(t, "gitea-minio", storage.Section.Key("MINIO_BUCKET").String())
 | 
				
			||||||
@@ -85,22 +88,24 @@ MINIO_BUCKET = gitea
 | 
				
			|||||||
[storage]
 | 
					[storage]
 | 
				
			||||||
STORAGE_TYPE = local
 | 
					STORAGE_TYPE = local
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
	Cfg, _ = ini.Load([]byte(iniStr))
 | 
						cfg, err := ini.Load([]byte(iniStr))
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sec := Cfg.Section("attachment")
 | 
						sec := cfg.Section("attachment")
 | 
				
			||||||
	storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
						storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
				
			||||||
	storage := getStorage("attachments", storageType, sec)
 | 
						storage := getStorage(cfg, "attachments", storageType, sec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.EqualValues(t, "minio", storage.Type)
 | 
						assert.EqualValues(t, "minio", storage.Type)
 | 
				
			||||||
	assert.EqualValues(t, "gitea-attachment", storage.Section.Key("MINIO_BUCKET").String())
 | 
						assert.EqualValues(t, "gitea-attachment", storage.Section.Key("MINIO_BUCKET").String())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Test_getStorageGetDefaults(t *testing.T) {
 | 
					func Test_getStorageGetDefaults(t *testing.T) {
 | 
				
			||||||
	Cfg, _ = ini.Load([]byte(""))
 | 
						cfg, err := ini.Load([]byte(""))
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sec := Cfg.Section("attachment")
 | 
						sec := cfg.Section("attachment")
 | 
				
			||||||
	storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
						storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
				
			||||||
	storage := getStorage("attachments", storageType, sec)
 | 
						storage := getStorage(cfg, "attachments", storageType, sec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.EqualValues(t, "gitea", storage.Section.Key("MINIO_BUCKET").String())
 | 
						assert.EqualValues(t, "gitea", storage.Section.Key("MINIO_BUCKET").String())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -116,26 +121,27 @@ MINIO_BUCKET = gitea-attachment
 | 
				
			|||||||
[storage]
 | 
					[storage]
 | 
				
			||||||
MINIO_BUCKET = gitea-storage
 | 
					MINIO_BUCKET = gitea-storage
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
	Cfg, _ = ini.Load([]byte(iniStr))
 | 
						cfg, err := ini.Load([]byte(iniStr))
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		sec := Cfg.Section("attachment")
 | 
							sec := cfg.Section("attachment")
 | 
				
			||||||
		storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
							storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
				
			||||||
		storage := getStorage("attachments", storageType, sec)
 | 
							storage := getStorage(cfg, "attachments", storageType, sec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assert.EqualValues(t, "gitea-attachment", storage.Section.Key("MINIO_BUCKET").String())
 | 
							assert.EqualValues(t, "gitea-attachment", storage.Section.Key("MINIO_BUCKET").String())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		sec := Cfg.Section("lfs")
 | 
							sec := cfg.Section("lfs")
 | 
				
			||||||
		storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
							storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
				
			||||||
		storage := getStorage("lfs", storageType, sec)
 | 
							storage := getStorage(cfg, "lfs", storageType, sec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assert.EqualValues(t, "gitea-lfs", storage.Section.Key("MINIO_BUCKET").String())
 | 
							assert.EqualValues(t, "gitea-lfs", storage.Section.Key("MINIO_BUCKET").String())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		sec := Cfg.Section("avatar")
 | 
							sec := cfg.Section("avatar")
 | 
				
			||||||
		storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
							storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
				
			||||||
		storage := getStorage("avatars", storageType, sec)
 | 
							storage := getStorage(cfg, "avatars", storageType, sec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assert.EqualValues(t, "gitea-storage", storage.Section.Key("MINIO_BUCKET").String())
 | 
							assert.EqualValues(t, "gitea-storage", storage.Section.Key("MINIO_BUCKET").String())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -149,19 +155,20 @@ STORAGE_TYPE = lfs
 | 
				
			|||||||
[storage.lfs]
 | 
					[storage.lfs]
 | 
				
			||||||
MINIO_BUCKET = gitea-storage
 | 
					MINIO_BUCKET = gitea-storage
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
	Cfg, _ = ini.Load([]byte(iniStr))
 | 
						cfg, err := ini.Load([]byte(iniStr))
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		sec := Cfg.Section("attachment")
 | 
							sec := cfg.Section("attachment")
 | 
				
			||||||
		storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
							storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
				
			||||||
		storage := getStorage("attachments", storageType, sec)
 | 
							storage := getStorage(cfg, "attachments", storageType, sec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assert.EqualValues(t, "gitea-storage", storage.Section.Key("MINIO_BUCKET").String())
 | 
							assert.EqualValues(t, "gitea-storage", storage.Section.Key("MINIO_BUCKET").String())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		sec := Cfg.Section("lfs")
 | 
							sec := cfg.Section("lfs")
 | 
				
			||||||
		storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
							storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
				
			||||||
		storage := getStorage("lfs", storageType, sec)
 | 
							storage := getStorage(cfg, "lfs", storageType, sec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assert.EqualValues(t, "gitea-storage", storage.Section.Key("MINIO_BUCKET").String())
 | 
							assert.EqualValues(t, "gitea-storage", storage.Section.Key("MINIO_BUCKET").String())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -172,11 +179,12 @@ func Test_getStorageInheritStorageType(t *testing.T) {
 | 
				
			|||||||
[storage]
 | 
					[storage]
 | 
				
			||||||
STORAGE_TYPE = minio
 | 
					STORAGE_TYPE = minio
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
	Cfg, _ = ini.Load([]byte(iniStr))
 | 
						cfg, err := ini.Load([]byte(iniStr))
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sec := Cfg.Section("attachment")
 | 
						sec := cfg.Section("attachment")
 | 
				
			||||||
	storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
						storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
				
			||||||
	storage := getStorage("attachments", storageType, sec)
 | 
						storage := getStorage(cfg, "attachments", storageType, sec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.EqualValues(t, "minio", storage.Type)
 | 
						assert.EqualValues(t, "minio", storage.Type)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -186,11 +194,12 @@ func Test_getStorageInheritNameSectionType(t *testing.T) {
 | 
				
			|||||||
[storage.attachments]
 | 
					[storage.attachments]
 | 
				
			||||||
STORAGE_TYPE = minio
 | 
					STORAGE_TYPE = minio
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
	Cfg, _ = ini.Load([]byte(iniStr))
 | 
						cfg, err := ini.Load([]byte(iniStr))
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sec := Cfg.Section("attachment")
 | 
						sec := cfg.Section("attachment")
 | 
				
			||||||
	storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
						storageType := sec.Key("STORAGE_TYPE").MustString("")
 | 
				
			||||||
	storage := getStorage("attachments", storageType, sec)
 | 
						storage := getStorage(cfg, "attachments", storageType, sec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.EqualValues(t, "minio", storage.Type)
 | 
						assert.EqualValues(t, "minio", storage.Type)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,13 +5,13 @@ package setting
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// FIXME: DEPRECATED to be removed in v1.18.0
 | 
					// FIXME: DEPRECATED to be removed in v1.18.0
 | 
				
			||||||
// - will need to set default for [queue.task] LENGTH to 1000 though
 | 
					// - will need to set default for [queue.task] LENGTH to 1000 though
 | 
				
			||||||
func newTaskService() {
 | 
					func loadTaskFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	taskSec := Cfg.Section("task")
 | 
						taskSec := rootCfg.Section("task")
 | 
				
			||||||
	queueTaskSec := Cfg.Section("queue.task")
 | 
						queueTaskSec := rootCfg.Section("queue.task")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	deprecatedSetting("task", "QUEUE_TYPE", "queue.task", "TYPE")
 | 
						deprecatedSetting(rootCfg, "task", "QUEUE_TYPE", "queue.task", "TYPE")
 | 
				
			||||||
	deprecatedSetting("task", "QUEUE_CONN_STR", "queue.task", "CONN_STR")
 | 
						deprecatedSetting(rootCfg, "task", "QUEUE_CONN_STR", "queue.task", "CONN_STR")
 | 
				
			||||||
	deprecatedSetting("task", "QUEUE_LENGTH", "queue.task", "LENGTH")
 | 
						deprecatedSetting(rootCfg, "task", "QUEUE_LENGTH", "queue.task", "LENGTH")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch taskSec.Key("QUEUE_TYPE").MustString("channel") {
 | 
						switch taskSec.Key("QUEUE_TYPE").MustString("channel") {
 | 
				
			||||||
	case "channel":
 | 
						case "channel":
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										64
									
								
								modules/setting/time.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								modules/setting/time.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
				
			|||||||
 | 
					// Copyright 2023 The Gitea Authors. All rights reserved.
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: MIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package setting
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						// Time settings
 | 
				
			||||||
 | 
						TimeFormat string
 | 
				
			||||||
 | 
						// UILocation is the location on the UI, so that we can display the time on UI.
 | 
				
			||||||
 | 
						DefaultUILocation = time.Local
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func loadTimeFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
 | 
						timeFormatKey := rootCfg.Section("time").Key("FORMAT").MustString("")
 | 
				
			||||||
 | 
						if timeFormatKey != "" {
 | 
				
			||||||
 | 
							TimeFormat = map[string]string{
 | 
				
			||||||
 | 
								"ANSIC":       time.ANSIC,
 | 
				
			||||||
 | 
								"UnixDate":    time.UnixDate,
 | 
				
			||||||
 | 
								"RubyDate":    time.RubyDate,
 | 
				
			||||||
 | 
								"RFC822":      time.RFC822,
 | 
				
			||||||
 | 
								"RFC822Z":     time.RFC822Z,
 | 
				
			||||||
 | 
								"RFC850":      time.RFC850,
 | 
				
			||||||
 | 
								"RFC1123":     time.RFC1123,
 | 
				
			||||||
 | 
								"RFC1123Z":    time.RFC1123Z,
 | 
				
			||||||
 | 
								"RFC3339":     time.RFC3339,
 | 
				
			||||||
 | 
								"RFC3339Nano": time.RFC3339Nano,
 | 
				
			||||||
 | 
								"Kitchen":     time.Kitchen,
 | 
				
			||||||
 | 
								"Stamp":       time.Stamp,
 | 
				
			||||||
 | 
								"StampMilli":  time.StampMilli,
 | 
				
			||||||
 | 
								"StampMicro":  time.StampMicro,
 | 
				
			||||||
 | 
								"StampNano":   time.StampNano,
 | 
				
			||||||
 | 
							}[timeFormatKey]
 | 
				
			||||||
 | 
							// When the TimeFormatKey does not exist in the previous map e.g.'2006-01-02 15:04:05'
 | 
				
			||||||
 | 
							if len(TimeFormat) == 0 {
 | 
				
			||||||
 | 
								TimeFormat = timeFormatKey
 | 
				
			||||||
 | 
								TestTimeFormat, _ := time.Parse(TimeFormat, TimeFormat)
 | 
				
			||||||
 | 
								if TestTimeFormat.Format(time.RFC3339) != "2006-01-02T15:04:05Z" {
 | 
				
			||||||
 | 
									log.Warn("Provided TimeFormat: %s does not create a fully specified date and time.", TimeFormat)
 | 
				
			||||||
 | 
									log.Warn("In order to display dates and times correctly please check your time format has 2006, 01, 02, 15, 04 and 05")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								log.Trace("Custom TimeFormat: %s", TimeFormat)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						zone := rootCfg.Section("time").Key("DEFAULT_UI_LOCATION").String()
 | 
				
			||||||
 | 
						if zone != "" {
 | 
				
			||||||
 | 
							var err error
 | 
				
			||||||
 | 
							DefaultUILocation, err = time.LoadLocation(zone)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								log.Fatal("Load time zone failed: %v", err)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								log.Info("Default UI Location is %v", zone)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if DefaultUILocation == nil {
 | 
				
			||||||
 | 
							DefaultUILocation = time.Local
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										152
									
								
								modules/setting/ui.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								modules/setting/ui.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,152 @@
 | 
				
			|||||||
 | 
					// Copyright 2023 The Gitea Authors. All rights reserved.
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: MIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package setting
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/container"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UI settings
 | 
				
			||||||
 | 
					var UI = struct {
 | 
				
			||||||
 | 
						ExplorePagingNum      int
 | 
				
			||||||
 | 
						SitemapPagingNum      int
 | 
				
			||||||
 | 
						IssuePagingNum        int
 | 
				
			||||||
 | 
						RepoSearchPagingNum   int
 | 
				
			||||||
 | 
						MembersPagingNum      int
 | 
				
			||||||
 | 
						FeedMaxCommitNum      int
 | 
				
			||||||
 | 
						FeedPagingNum         int
 | 
				
			||||||
 | 
						PackagesPagingNum     int
 | 
				
			||||||
 | 
						GraphMaxCommitNum     int
 | 
				
			||||||
 | 
						CodeCommentLines      int
 | 
				
			||||||
 | 
						ReactionMaxUserNum    int
 | 
				
			||||||
 | 
						ThemeColorMetaTag     string
 | 
				
			||||||
 | 
						MaxDisplayFileSize    int64
 | 
				
			||||||
 | 
						ShowUserEmail         bool
 | 
				
			||||||
 | 
						DefaultShowFullName   bool
 | 
				
			||||||
 | 
						DefaultTheme          string
 | 
				
			||||||
 | 
						Themes                []string
 | 
				
			||||||
 | 
						Reactions             []string
 | 
				
			||||||
 | 
						ReactionsLookup       container.Set[string] `ini:"-"`
 | 
				
			||||||
 | 
						CustomEmojis          []string
 | 
				
			||||||
 | 
						CustomEmojisMap       map[string]string `ini:"-"`
 | 
				
			||||||
 | 
						SearchRepoDescription bool
 | 
				
			||||||
 | 
						UseServiceWorker      bool
 | 
				
			||||||
 | 
						OnlyShowRelevantRepos bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Notification struct {
 | 
				
			||||||
 | 
							MinTimeout            time.Duration
 | 
				
			||||||
 | 
							TimeoutStep           time.Duration
 | 
				
			||||||
 | 
							MaxTimeout            time.Duration
 | 
				
			||||||
 | 
							EventSourceUpdateTime time.Duration
 | 
				
			||||||
 | 
						} `ini:"ui.notification"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SVG struct {
 | 
				
			||||||
 | 
							Enabled bool `ini:"ENABLE_RENDER"`
 | 
				
			||||||
 | 
						} `ini:"ui.svg"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						CSV struct {
 | 
				
			||||||
 | 
							MaxFileSize int64
 | 
				
			||||||
 | 
						} `ini:"ui.csv"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Admin struct {
 | 
				
			||||||
 | 
							UserPagingNum   int
 | 
				
			||||||
 | 
							RepoPagingNum   int
 | 
				
			||||||
 | 
							NoticePagingNum int
 | 
				
			||||||
 | 
							OrgPagingNum    int
 | 
				
			||||||
 | 
						} `ini:"ui.admin"`
 | 
				
			||||||
 | 
						User struct {
 | 
				
			||||||
 | 
							RepoPagingNum int
 | 
				
			||||||
 | 
						} `ini:"ui.user"`
 | 
				
			||||||
 | 
						Meta struct {
 | 
				
			||||||
 | 
							Author      string
 | 
				
			||||||
 | 
							Description string
 | 
				
			||||||
 | 
							Keywords    string
 | 
				
			||||||
 | 
						} `ini:"ui.meta"`
 | 
				
			||||||
 | 
					}{
 | 
				
			||||||
 | 
						ExplorePagingNum:    20,
 | 
				
			||||||
 | 
						SitemapPagingNum:    20,
 | 
				
			||||||
 | 
						IssuePagingNum:      20,
 | 
				
			||||||
 | 
						RepoSearchPagingNum: 20,
 | 
				
			||||||
 | 
						MembersPagingNum:    20,
 | 
				
			||||||
 | 
						FeedMaxCommitNum:    5,
 | 
				
			||||||
 | 
						FeedPagingNum:       20,
 | 
				
			||||||
 | 
						PackagesPagingNum:   20,
 | 
				
			||||||
 | 
						GraphMaxCommitNum:   100,
 | 
				
			||||||
 | 
						CodeCommentLines:    4,
 | 
				
			||||||
 | 
						ReactionMaxUserNum:  10,
 | 
				
			||||||
 | 
						ThemeColorMetaTag:   `#6cc644`,
 | 
				
			||||||
 | 
						MaxDisplayFileSize:  8388608,
 | 
				
			||||||
 | 
						DefaultTheme:        `auto`,
 | 
				
			||||||
 | 
						Themes:              []string{`auto`, `gitea`, `arc-green`},
 | 
				
			||||||
 | 
						Reactions:           []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`},
 | 
				
			||||||
 | 
						CustomEmojis:        []string{`git`, `gitea`, `codeberg`, `gitlab`, `github`, `gogs`},
 | 
				
			||||||
 | 
						CustomEmojisMap:     map[string]string{"git": ":git:", "gitea": ":gitea:", "codeberg": ":codeberg:", "gitlab": ":gitlab:", "github": ":github:", "gogs": ":gogs:"},
 | 
				
			||||||
 | 
						Notification: struct {
 | 
				
			||||||
 | 
							MinTimeout            time.Duration
 | 
				
			||||||
 | 
							TimeoutStep           time.Duration
 | 
				
			||||||
 | 
							MaxTimeout            time.Duration
 | 
				
			||||||
 | 
							EventSourceUpdateTime time.Duration
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							MinTimeout:            10 * time.Second,
 | 
				
			||||||
 | 
							TimeoutStep:           10 * time.Second,
 | 
				
			||||||
 | 
							MaxTimeout:            60 * time.Second,
 | 
				
			||||||
 | 
							EventSourceUpdateTime: 10 * time.Second,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						SVG: struct {
 | 
				
			||||||
 | 
							Enabled bool `ini:"ENABLE_RENDER"`
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							Enabled: true,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						CSV: struct {
 | 
				
			||||||
 | 
							MaxFileSize int64
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							MaxFileSize: 524288,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						Admin: struct {
 | 
				
			||||||
 | 
							UserPagingNum   int
 | 
				
			||||||
 | 
							RepoPagingNum   int
 | 
				
			||||||
 | 
							NoticePagingNum int
 | 
				
			||||||
 | 
							OrgPagingNum    int
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							UserPagingNum:   50,
 | 
				
			||||||
 | 
							RepoPagingNum:   50,
 | 
				
			||||||
 | 
							NoticePagingNum: 25,
 | 
				
			||||||
 | 
							OrgPagingNum:    50,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						User: struct {
 | 
				
			||||||
 | 
							RepoPagingNum int
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							RepoPagingNum: 15,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						Meta: struct {
 | 
				
			||||||
 | 
							Author      string
 | 
				
			||||||
 | 
							Description string
 | 
				
			||||||
 | 
							Keywords    string
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							Author:      "Gitea - Git with a cup of tea",
 | 
				
			||||||
 | 
							Description: "Gitea (Git with a cup of tea) is a painless self-hosted Git service written in Go",
 | 
				
			||||||
 | 
							Keywords:    "go,git,self-hosted,gitea",
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func loadUIFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
 | 
						mustMapSetting(rootCfg, "ui", &UI)
 | 
				
			||||||
 | 
						sec := rootCfg.Section("ui")
 | 
				
			||||||
 | 
						UI.ShowUserEmail = sec.Key("SHOW_USER_EMAIL").MustBool(true)
 | 
				
			||||||
 | 
						UI.DefaultShowFullName = sec.Key("DEFAULT_SHOW_FULL_NAME").MustBool(false)
 | 
				
			||||||
 | 
						UI.SearchRepoDescription = sec.Key("SEARCH_REPO_DESCRIPTION").MustBool(true)
 | 
				
			||||||
 | 
						UI.UseServiceWorker = sec.Key("USE_SERVICE_WORKER").MustBool(false)
 | 
				
			||||||
 | 
						UI.OnlyShowRelevantRepos = sec.Key("ONLY_SHOW_RELEVANT_REPOS").MustBool(false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						UI.ReactionsLookup = make(container.Set[string])
 | 
				
			||||||
 | 
						for _, reaction := range UI.Reactions {
 | 
				
			||||||
 | 
							UI.ReactionsLookup.Add(reaction)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						UI.CustomEmojisMap = make(map[string]string)
 | 
				
			||||||
 | 
						for _, emoji := range UI.CustomEmojis {
 | 
				
			||||||
 | 
							UI.CustomEmojisMap[emoji] = ":" + emoji + ":"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -29,8 +29,8 @@ var Webhook = struct {
 | 
				
			|||||||
	ProxyHosts:     []string{},
 | 
						ProxyHosts:     []string{},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newWebhookService() {
 | 
					func loadWebhookFrom(rootCfg ConfigProvider) {
 | 
				
			||||||
	sec := Cfg.Section("webhook")
 | 
						sec := rootCfg.Section("webhook")
 | 
				
			||||||
	Webhook.QueueLength = sec.Key("QUEUE_LENGTH").MustInt(1000)
 | 
						Webhook.QueueLength = sec.Key("QUEUE_LENGTH").MustInt(1000)
 | 
				
			||||||
	Webhook.DeliverTimeout = sec.Key("DELIVER_TIMEOUT").MustInt(5)
 | 
						Webhook.DeliverTimeout = sec.Key("DELIVER_TIMEOUT").MustInt(5)
 | 
				
			||||||
	Webhook.SkipTLSVerify = sec.Key("SKIP_TLS_VERIFY").MustBool()
 | 
						Webhook.SkipTLSVerify = sec.Key("SKIP_TLS_VERIFY").MustBool()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,8 +13,8 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestMain(m *testing.M) {
 | 
					func TestMain(m *testing.M) {
 | 
				
			||||||
	setting.LoadForTest()
 | 
						setting.InitProviderAndLoadCommonSettingsForTest()
 | 
				
			||||||
	setting.NewQueueService()
 | 
						setting.LoadQueueSettings()
 | 
				
			||||||
	unittest.MainTest(m, &unittest.TestOptions{
 | 
						unittest.MainTest(m, &unittest.TestOptions{
 | 
				
			||||||
		GiteaRootPath: filepath.Join("..", "..", "..", ".."),
 | 
							GiteaRootPath: filepath.Join("..", "..", "..", ".."),
 | 
				
			||||||
		SetUp:         webhook_service.Init,
 | 
							SetUp:         webhook_service.Init,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,11 +50,11 @@ func Middlewares() []func(http.Handler) http.Handler {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	handlers = append(handlers, middleware.StripSlashes)
 | 
						handlers = append(handlers, middleware.StripSlashes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if !setting.DisableRouterLog {
 | 
						if !setting.Log.DisableRouterLog {
 | 
				
			||||||
		handlers = append(handlers, routing.NewLoggerHandler())
 | 
							handlers = append(handlers, routing.NewLoggerHandler())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if setting.EnableAccessLog {
 | 
						if setting.Log.EnableAccessLog {
 | 
				
			||||||
		handlers = append(handlers, context.AccessLogger())
 | 
							handlers = append(handlers, context.AccessLogger())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -73,7 +73,7 @@ func mustInitCtx(ctx context.Context, fn func(ctx context.Context) error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// InitGitServices init new services for git, this is also called in `contrib/pr/checkout.go`
 | 
					// InitGitServices init new services for git, this is also called in `contrib/pr/checkout.go`
 | 
				
			||||||
func InitGitServices() {
 | 
					func InitGitServices() {
 | 
				
			||||||
	setting.NewServices()
 | 
						setting.LoadSettings()
 | 
				
			||||||
	mustInit(storage.Init)
 | 
						mustInit(storage.Init)
 | 
				
			||||||
	mustInit(repo_service.Init)
 | 
						mustInit(repo_service.Init)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -119,7 +119,7 @@ func GlobalInitInstalled(ctx context.Context) {
 | 
				
			|||||||
	log.Info("AppPath: %s", setting.AppPath)
 | 
						log.Info("AppPath: %s", setting.AppPath)
 | 
				
			||||||
	log.Info("AppWorkPath: %s", setting.AppWorkPath)
 | 
						log.Info("AppWorkPath: %s", setting.AppWorkPath)
 | 
				
			||||||
	log.Info("Custom path: %s", setting.CustomPath)
 | 
						log.Info("Custom path: %s", setting.CustomPath)
 | 
				
			||||||
	log.Info("Log path: %s", setting.LogRootPath)
 | 
						log.Info("Log path: %s", setting.Log.RootPath)
 | 
				
			||||||
	log.Info("Configuration file: %s", setting.CustomConf)
 | 
						log.Info("Configuration file: %s", setting.CustomConf)
 | 
				
			||||||
	log.Info("Run Mode: %s", util.ToTitleCase(setting.RunMode))
 | 
						log.Info("Run Mode: %s", util.ToTitleCase(setting.RunMode))
 | 
				
			||||||
	log.Info("Gitea v%s%s", setting.AppVer, setting.AppBuiltWith)
 | 
						log.Info("Gitea v%s%s", setting.AppVer, setting.AppBuiltWith)
 | 
				
			||||||
@@ -127,7 +127,7 @@ func GlobalInitInstalled(ctx context.Context) {
 | 
				
			|||||||
	// Setup i18n
 | 
						// Setup i18n
 | 
				
			||||||
	translation.InitLocales(ctx)
 | 
						translation.InitLocales(ctx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setting.NewServices()
 | 
						setting.LoadSettings()
 | 
				
			||||||
	mustInit(storage.Init)
 | 
						mustInit(storage.Init)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mailer.NewContext(ctx)
 | 
						mailer.NewContext(ctx)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -134,7 +134,7 @@ func Install(ctx *context.Context) {
 | 
				
			|||||||
	form.SSHPort = setting.SSH.Port
 | 
						form.SSHPort = setting.SSH.Port
 | 
				
			||||||
	form.HTTPPort = setting.HTTPPort
 | 
						form.HTTPPort = setting.HTTPPort
 | 
				
			||||||
	form.AppURL = setting.AppURL
 | 
						form.AppURL = setting.AppURL
 | 
				
			||||||
	form.LogRootPath = setting.LogRootPath
 | 
						form.LogRootPath = setting.Log.RootPath
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// E-mail service settings
 | 
						// E-mail service settings
 | 
				
			||||||
	if setting.MailService != nil {
 | 
						if setting.MailService != nil {
 | 
				
			||||||
@@ -467,7 +467,7 @@ func SubmitInstall(ctx *context.Context) {
 | 
				
			|||||||
	cfg.Section("session").Key("PROVIDER").SetValue("file")
 | 
						cfg.Section("session").Key("PROVIDER").SetValue("file")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg.Section("log").Key("MODE").SetValue("console")
 | 
						cfg.Section("log").Key("MODE").SetValue("console")
 | 
				
			||||||
	cfg.Section("log").Key("LEVEL").SetValue(setting.LogLevel.String())
 | 
						cfg.Section("log").Key("LEVEL").SetValue(setting.Log.Level.String())
 | 
				
			||||||
	cfg.Section("log").Key("ROOT_PATH").SetValue(form.LogRootPath)
 | 
						cfg.Section("log").Key("ROOT_PATH").SetValue(form.LogRootPath)
 | 
				
			||||||
	cfg.Section("log").Key("ROUTER").SetValue("console")
 | 
						cfg.Section("log").Key("ROUTER").SetValue("console")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,20 +15,21 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// PreloadSettings preloads the configuration to check if we need to run install
 | 
					// PreloadSettings preloads the configuration to check if we need to run install
 | 
				
			||||||
func PreloadSettings(ctx context.Context) bool {
 | 
					func PreloadSettings(ctx context.Context) bool {
 | 
				
			||||||
	setting.LoadAllowEmpty()
 | 
						setting.InitProviderAllowEmpty()
 | 
				
			||||||
 | 
						setting.LoadCommonSettings()
 | 
				
			||||||
	if !setting.InstallLock {
 | 
						if !setting.InstallLock {
 | 
				
			||||||
		log.Info("AppPath: %s", setting.AppPath)
 | 
							log.Info("AppPath: %s", setting.AppPath)
 | 
				
			||||||
		log.Info("AppWorkPath: %s", setting.AppWorkPath)
 | 
							log.Info("AppWorkPath: %s", setting.AppWorkPath)
 | 
				
			||||||
		log.Info("Custom path: %s", setting.CustomPath)
 | 
							log.Info("Custom path: %s", setting.CustomPath)
 | 
				
			||||||
		log.Info("Log path: %s", setting.LogRootPath)
 | 
							log.Info("Log path: %s", setting.Log.RootPath)
 | 
				
			||||||
		log.Info("Configuration file: %s", setting.CustomConf)
 | 
							log.Info("Configuration file: %s", setting.CustomConf)
 | 
				
			||||||
		log.Info("Prepare to run install page")
 | 
							log.Info("Prepare to run install page")
 | 
				
			||||||
		translation.InitLocales(ctx)
 | 
							translation.InitLocales(ctx)
 | 
				
			||||||
		if setting.EnableSQLite3 {
 | 
							if setting.EnableSQLite3 {
 | 
				
			||||||
			log.Info("SQLite3 is supported")
 | 
								log.Info("SQLite3 is supported")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		setting.InitDBConfig()
 | 
					
 | 
				
			||||||
		setting.NewServicesForInstall()
 | 
							setting.LoadSettingsForInstall()
 | 
				
			||||||
		svg.Init()
 | 
							svg.Init()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -37,8 +38,9 @@ func PreloadSettings(ctx context.Context) bool {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// reloadSettings reloads the existing settings and starts up the database
 | 
					// reloadSettings reloads the existing settings and starts up the database
 | 
				
			||||||
func reloadSettings(ctx context.Context) {
 | 
					func reloadSettings(ctx context.Context) {
 | 
				
			||||||
	setting.LoadFromExisting()
 | 
						setting.InitProviderFromExistingFile()
 | 
				
			||||||
	setting.InitDBConfig()
 | 
						setting.LoadCommonSettings()
 | 
				
			||||||
 | 
						setting.LoadDBSetting()
 | 
				
			||||||
	if setting.InstallLock {
 | 
						if setting.InstallLock {
 | 
				
			||||||
		if err := common.InitDBEngine(ctx); err == nil {
 | 
							if err := common.InitDBEngine(ctx); err == nil {
 | 
				
			||||||
			log.Info("ORM engine initialization successful!")
 | 
								log.Info("ORM engine initialization successful!")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -116,11 +116,11 @@ func AddLogger(ctx *context.PrivateContext) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if _, ok := opts.Config["level"]; !ok {
 | 
						if _, ok := opts.Config["level"]; !ok {
 | 
				
			||||||
		opts.Config["level"] = setting.LogLevel
 | 
							opts.Config["level"] = setting.Log.Level
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if _, ok := opts.Config["stacktraceLevel"]; !ok {
 | 
						if _, ok := opts.Config["stacktraceLevel"]; !ok {
 | 
				
			||||||
		opts.Config["stacktraceLevel"] = setting.StacktraceLogLevel
 | 
							opts.Config["stacktraceLevel"] = setting.Log.StacktraceLogLevel
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if opts.Mode == "file" {
 | 
						if opts.Mode == "file" {
 | 
				
			||||||
@@ -135,7 +135,7 @@ func AddLogger(ctx *context.PrivateContext) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bufferLen := setting.Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000)
 | 
						bufferLen := setting.Log.BufferLength
 | 
				
			||||||
	byteConfig, err := json.Marshal(opts.Config)
 | 
						byteConfig, err := json.Marshal(opts.Config)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Error("Failed to marshal log configuration: %v %v", opts.Config, err)
 | 
							log.Error("Failed to marshal log configuration: %v %v", opts.Config, err)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// SSHLog hook to response ssh log
 | 
					// SSHLog hook to response ssh log
 | 
				
			||||||
func SSHLog(ctx *context.PrivateContext) {
 | 
					func SSHLog(ctx *context.PrivateContext) {
 | 
				
			||||||
	if !setting.EnableSSHLog {
 | 
						if !setting.Log.EnableSSHLog {
 | 
				
			||||||
		ctx.Status(http.StatusOK)
 | 
							ctx.Status(http.StatusOK)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -117,7 +117,7 @@ func Config(ctx *context.Context) {
 | 
				
			|||||||
	ctx.Data["AppUrl"] = setting.AppURL
 | 
						ctx.Data["AppUrl"] = setting.AppURL
 | 
				
			||||||
	ctx.Data["Domain"] = setting.Domain
 | 
						ctx.Data["Domain"] = setting.Domain
 | 
				
			||||||
	ctx.Data["OfflineMode"] = setting.OfflineMode
 | 
						ctx.Data["OfflineMode"] = setting.OfflineMode
 | 
				
			||||||
	ctx.Data["DisableRouterLog"] = setting.DisableRouterLog
 | 
						ctx.Data["DisableRouterLog"] = setting.Log.DisableRouterLog
 | 
				
			||||||
	ctx.Data["RunUser"] = setting.RunUser
 | 
						ctx.Data["RunUser"] = setting.RunUser
 | 
				
			||||||
	ctx.Data["RunMode"] = util.ToTitleCase(setting.RunMode)
 | 
						ctx.Data["RunMode"] = util.ToTitleCase(setting.RunMode)
 | 
				
			||||||
	ctx.Data["GitVersion"] = git.VersionInfo()
 | 
						ctx.Data["GitVersion"] = git.VersionInfo()
 | 
				
			||||||
@@ -125,7 +125,7 @@ func Config(ctx *context.Context) {
 | 
				
			|||||||
	ctx.Data["RepoRootPath"] = setting.RepoRootPath
 | 
						ctx.Data["RepoRootPath"] = setting.RepoRootPath
 | 
				
			||||||
	ctx.Data["CustomRootPath"] = setting.CustomPath
 | 
						ctx.Data["CustomRootPath"] = setting.CustomPath
 | 
				
			||||||
	ctx.Data["StaticRootPath"] = setting.StaticRootPath
 | 
						ctx.Data["StaticRootPath"] = setting.StaticRootPath
 | 
				
			||||||
	ctx.Data["LogRootPath"] = setting.LogRootPath
 | 
						ctx.Data["LogRootPath"] = setting.Log.RootPath
 | 
				
			||||||
	ctx.Data["ScriptType"] = setting.ScriptType
 | 
						ctx.Data["ScriptType"] = setting.ScriptType
 | 
				
			||||||
	ctx.Data["ReverseProxyAuthUser"] = setting.ReverseProxyAuthUser
 | 
						ctx.Data["ReverseProxyAuthUser"] = setting.ReverseProxyAuthUser
 | 
				
			||||||
	ctx.Data["ReverseProxyAuthEmail"] = setting.ReverseProxyAuthEmail
 | 
						ctx.Data["ReverseProxyAuthEmail"] = setting.ReverseProxyAuthEmail
 | 
				
			||||||
@@ -183,10 +183,10 @@ func Config(ctx *context.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	ctx.Data["EnvVars"] = envVars
 | 
						ctx.Data["EnvVars"] = envVars
 | 
				
			||||||
	ctx.Data["Loggers"] = setting.GetLogDescriptions()
 | 
						ctx.Data["Loggers"] = setting.GetLogDescriptions()
 | 
				
			||||||
	ctx.Data["EnableAccessLog"] = setting.EnableAccessLog
 | 
						ctx.Data["EnableAccessLog"] = setting.Log.EnableAccessLog
 | 
				
			||||||
	ctx.Data["AccessLogTemplate"] = setting.AccessLogTemplate
 | 
						ctx.Data["AccessLogTemplate"] = setting.Log.AccessLogTemplate
 | 
				
			||||||
	ctx.Data["DisableRouterLog"] = setting.DisableRouterLog
 | 
						ctx.Data["DisableRouterLog"] = setting.Log.DisableRouterLog
 | 
				
			||||||
	ctx.Data["EnableXORMLog"] = setting.EnableXORMLog
 | 
						ctx.Data["EnableXORMLog"] = setting.Log.EnableXORMLog
 | 
				
			||||||
	ctx.Data["LogSQL"] = setting.Database.LogSQL
 | 
						ctx.Data["LogSQL"] = setting.Database.LogSQL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.HTML(http.StatusOK, tplConfig)
 | 
						ctx.HTML(http.StatusOK, tplConfig)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,8 +15,8 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestMain(m *testing.M) {
 | 
					func TestMain(m *testing.M) {
 | 
				
			||||||
	setting.LoadForTest()
 | 
						setting.InitProviderAndLoadCommonSettingsForTest()
 | 
				
			||||||
	setting.NewQueueService()
 | 
						setting.LoadQueueSettings()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// for tests, allow only loopback IPs
 | 
						// for tests, allow only loopback IPs
 | 
				
			||||||
	setting.Webhook.AllowedHostList = hostmatcher.MatchBuiltinLoopback
 | 
						setting.Webhook.AllowedHostList = hostmatcher.MatchBuiltinLoopback
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -87,8 +87,8 @@ func TestMain(m *testing.M) {
 | 
				
			|||||||
	c = routers.NormalRoutes(context.TODO())
 | 
						c = routers.NormalRoutes(context.TODO())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// integration test settings...
 | 
						// integration test settings...
 | 
				
			||||||
	if setting.Cfg != nil {
 | 
						if setting.CfgProvider != nil {
 | 
				
			||||||
		testingCfg := setting.Cfg.Section("integration-tests")
 | 
							testingCfg := setting.CfgProvider.Section("integration-tests")
 | 
				
			||||||
		tests.SlowTest = testingCfg.Key("SLOW_TEST").MustDuration(tests.SlowTest)
 | 
							tests.SlowTest = testingCfg.Key("SLOW_TEST").MustDuration(tests.SlowTest)
 | 
				
			||||||
		tests.SlowFlush = testingCfg.Key("SLOW_FLUSH").MustDuration(tests.SlowFlush)
 | 
							tests.SlowFlush = testingCfg.Key("SLOW_FLUSH").MustDuration(tests.SlowFlush)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,7 +57,7 @@ func initMigrationTest(t *testing.T) func() {
 | 
				
			|||||||
		setting.CustomConf = giteaConf
 | 
							setting.CustomConf = giteaConf
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setting.LoadForTest()
 | 
						setting.InitProviderAndLoadCommonSettingsForTest()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.True(t, len(setting.RepoRootPath) != 0)
 | 
						assert.True(t, len(setting.RepoRootPath) != 0)
 | 
				
			||||||
	assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
 | 
						assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
 | 
				
			||||||
@@ -83,8 +83,8 @@ func initMigrationTest(t *testing.T) func() {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.NoError(t, git.InitFull(context.Background()))
 | 
						assert.NoError(t, git.InitFull(context.Background()))
 | 
				
			||||||
	setting.InitDBConfig()
 | 
						setting.LoadDBSetting()
 | 
				
			||||||
	setting.NewLogServices(true)
 | 
						setting.InitLogs(true)
 | 
				
			||||||
	return deferFn
 | 
						return deferFn
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -292,7 +292,7 @@ func doMigrationTest(t *testing.T, version string) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setting.NewXORMLogService(false)
 | 
						setting.InitSQLLog(false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err := db.InitEngineWithMigration(context.Background(), wrappedMigrate)
 | 
						err := db.InitEngineWithMigration(context.Background(), wrappedMigrate)
 | 
				
			||||||
	assert.NoError(t, err)
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,7 +57,7 @@ func InitTest(requireGitea bool) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setting.SetCustomPathAndConf("", "", "")
 | 
						setting.SetCustomPathAndConf("", "", "")
 | 
				
			||||||
	setting.LoadForTest()
 | 
						setting.InitProviderAndLoadCommonSettingsForTest()
 | 
				
			||||||
	setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master"
 | 
						setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master"
 | 
				
			||||||
	_ = util.RemoveAll(repo_module.LocalCopyPath())
 | 
						_ = util.RemoveAll(repo_module.LocalCopyPath())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -65,7 +65,7 @@ func InitTest(requireGitea bool) {
 | 
				
			|||||||
		log.Fatal("git.InitOnceWithSync: %v", err)
 | 
							log.Fatal("git.InitOnceWithSync: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setting.InitDBConfig()
 | 
						setting.LoadDBSetting()
 | 
				
			||||||
	if err := storage.Init(); err != nil {
 | 
						if err := storage.Init(); err != nil {
 | 
				
			||||||
		fmt.Printf("Init storage failed: %v", err)
 | 
							fmt.Printf("Init storage failed: %v", err)
 | 
				
			||||||
		os.Exit(1)
 | 
							os.Exit(1)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user