code.gitea.io/gitea@v1.22.3/modules/setting/setting.go (about) 1 // Copyright 2014 The Gogs Authors. All rights reserved. 2 // Copyright 2017 The Gitea Authors. All rights reserved. 3 // SPDX-License-Identifier: MIT 4 5 package setting 6 7 import ( 8 "fmt" 9 "os" 10 "runtime" 11 "strings" 12 "time" 13 14 "code.gitea.io/gitea/modules/log" 15 "code.gitea.io/gitea/modules/user" 16 "code.gitea.io/gitea/modules/util" 17 ) 18 19 // settings 20 var ( 21 // AppVer is the version of the current build of Gitea. It is set in main.go from main.Version. 22 AppVer string 23 // AppBuiltWith represents a human-readable version go runtime build version and build tags. (See main.go formatBuiltWith().) 24 AppBuiltWith string 25 // AppStartTime store time gitea has started 26 AppStartTime time.Time 27 28 // Other global setting objects 29 30 CfgProvider ConfigProvider 31 RunMode string 32 RunUser string 33 IsProd bool 34 IsWindows bool 35 36 // IsInTesting indicates whether the testing is running. A lot of unreliable code causes a lot of nonsense error logs during testing 37 // TODO: this is only a temporary solution, we should make the test code more reliable 38 IsInTesting = false 39 ) 40 41 func init() { 42 IsWindows = runtime.GOOS == "windows" 43 if AppVer == "" { 44 AppVer = "dev" 45 } 46 47 // We can rely on log.CanColorStdout being set properly because modules/log/console_windows.go comes before modules/setting/setting.go lexicographically 48 // By default set this logger at Info - we'll change it later, but we need to start with something. 49 log.SetConsoleLogger(log.DEFAULT, "console", log.INFO) 50 } 51 52 // IsRunUserMatchCurrentUser returns false if configured run user does not match 53 // actual user that runs the app. The first return value is the actual user name. 54 // This check is ignored under Windows since SSH remote login is not the main 55 // method to login on Windows. 56 func IsRunUserMatchCurrentUser(runUser string) (string, bool) { 57 if IsWindows || SSH.StartBuiltinServer { 58 return "", true 59 } 60 61 currentUser := user.CurrentUsername() 62 return currentUser, runUser == currentUser 63 } 64 65 // PrepareAppDataPath creates app data directory if necessary 66 func PrepareAppDataPath() error { 67 // FIXME: There are too many calls to MkdirAll in old code. It is incorrect. 68 // For example, if someDir=/mnt/vol1/gitea-home/data, if the mount point /mnt/vol1 is not mounted when Gitea runs, 69 // then gitea will make new empty directories in /mnt/vol1, all are stored in the root filesystem. 70 // The correct behavior should be: creating parent directories is end users' duty. We only create sub-directories in existing parent directories. 71 // For quickstart, the parent directories should be created automatically for first startup (eg: a flag or a check of INSTALL_LOCK). 72 // 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. 73 74 st, err := os.Stat(AppDataPath) 75 if os.IsNotExist(err) { 76 err = os.MkdirAll(AppDataPath, os.ModePerm) 77 if err != nil { 78 return fmt.Errorf("unable to create the APP_DATA_PATH directory: %q, Error: %w", AppDataPath, err) 79 } 80 return nil 81 } 82 83 if err != nil { 84 return fmt.Errorf("unable to use APP_DATA_PATH %q. Error: %w", AppDataPath, err) 85 } 86 87 if !st.IsDir() /* also works for symlink */ { 88 return fmt.Errorf("the APP_DATA_PATH %q is not a directory (or symlink to a directory) and can't be used", AppDataPath) 89 } 90 91 return nil 92 } 93 94 func InitCfgProvider(file string) { 95 var err error 96 if CfgProvider, err = NewConfigProviderFromFile(file); err != nil { 97 log.Fatal("Unable to init config provider from %q: %v", file, err) 98 } 99 CfgProvider.DisableSaving() // do not allow saving the CfgProvider into file, it will be polluted by the "MustXxx" calls 100 } 101 102 func MustInstalled() { 103 if !InstallLock { 104 log.Fatal(`Unable to load config file for a installed Gitea instance, you should either use "--config" to set your config file (app.ini), or run "gitea web" command to install Gitea.`) 105 } 106 } 107 108 func LoadCommonSettings() { 109 if err := loadCommonSettingsFrom(CfgProvider); err != nil { 110 log.Fatal("Unable to load settings from config: %v", err) 111 } 112 } 113 114 // loadCommonSettingsFrom loads common configurations from a configuration provider. 115 func loadCommonSettingsFrom(cfg ConfigProvider) error { 116 // WARNING: don't change the sequence except you know what you are doing. 117 loadRunModeFrom(cfg) 118 loadLogGlobalFrom(cfg) 119 loadServerFrom(cfg) 120 loadSSHFrom(cfg) 121 122 mustCurrentRunUserMatch(cfg) // it depends on the SSH config, only non-builtin SSH server requires this check 123 124 loadOAuth2From(cfg) 125 loadSecurityFrom(cfg) 126 if err := loadAttachmentFrom(cfg); err != nil { 127 return err 128 } 129 if err := loadLFSFrom(cfg); err != nil { 130 return err 131 } 132 loadTimeFrom(cfg) 133 loadRepositoryFrom(cfg) 134 if err := loadAvatarsFrom(cfg); err != nil { 135 return err 136 } 137 if err := loadRepoAvatarFrom(cfg); err != nil { 138 return err 139 } 140 if err := loadPackagesFrom(cfg); err != nil { 141 return err 142 } 143 if err := loadActionsFrom(cfg); err != nil { 144 return err 145 } 146 loadUIFrom(cfg) 147 loadAdminFrom(cfg) 148 loadAPIFrom(cfg) 149 loadMetricsFrom(cfg) 150 loadCamoFrom(cfg) 151 loadI18nFrom(cfg) 152 loadGitFrom(cfg) 153 loadMirrorFrom(cfg) 154 loadMarkupFrom(cfg) 155 loadOtherFrom(cfg) 156 return nil 157 } 158 159 func loadRunModeFrom(rootCfg ConfigProvider) { 160 rootSec := rootCfg.Section("") 161 RunUser = rootSec.Key("RUN_USER").MustString(user.CurrentUsername()) 162 163 // The following is a purposefully undocumented option. Please do not run Gitea as root. It will only cause future headaches. 164 // Please don't use root as a bandaid to "fix" something that is broken, instead the broken thing should instead be fixed properly. 165 unsafeAllowRunAsRoot := ConfigSectionKeyBool(rootSec, "I_AM_BEING_UNSAFE_RUNNING_AS_ROOT") 166 unsafeAllowRunAsRoot = unsafeAllowRunAsRoot || util.OptionalBoolParse(os.Getenv("GITEA_I_AM_BEING_UNSAFE_RUNNING_AS_ROOT")).Value() 167 RunMode = os.Getenv("GITEA_RUN_MODE") 168 if RunMode == "" { 169 RunMode = rootSec.Key("RUN_MODE").MustString("prod") 170 } 171 172 // non-dev mode is treated as prod mode, to protect users from accidentally running in dev mode if there is a typo in this value. 173 RunMode = strings.ToLower(RunMode) 174 if RunMode != "dev" { 175 RunMode = "prod" 176 } 177 IsProd = RunMode != "dev" 178 179 // check if we run as root 180 if os.Getuid() == 0 { 181 if !unsafeAllowRunAsRoot { 182 // Special thanks to VLC which inspired the wording of this messaging. 183 log.Fatal("Gitea is not supposed to be run as root. Sorry. If you need to use privileged TCP ports please instead use setcap and the `cap_net_bind_service` permission") 184 } 185 log.Critical("You are running Gitea using the root user, and have purposely chosen to skip built-in protections around this. You have been warned against this.") 186 } 187 } 188 189 // HasInstallLock checks the install-lock in ConfigProvider directly, because sometimes the config file is not loaded into setting variables yet. 190 func HasInstallLock(rootCfg ConfigProvider) bool { 191 return rootCfg.Section("security").Key("INSTALL_LOCK").MustBool(false) 192 } 193 194 func mustCurrentRunUserMatch(rootCfg ConfigProvider) { 195 // Does not check run user when the "InstallLock" is off. 196 if HasInstallLock(rootCfg) { 197 currentUser, match := IsRunUserMatchCurrentUser(RunUser) 198 if !match { 199 log.Fatal("Expect user '%s' but current user is: %s", RunUser, currentUser) 200 } 201 } 202 } 203 204 // LoadSettings initializes the settings for normal start up 205 func LoadSettings() { 206 initAllLoggers() 207 208 loadDBSetting(CfgProvider) 209 loadServiceFrom(CfgProvider) 210 loadOAuth2ClientFrom(CfgProvider) 211 loadCacheFrom(CfgProvider) 212 loadSessionFrom(CfgProvider) 213 loadCorsFrom(CfgProvider) 214 loadMailsFrom(CfgProvider) 215 loadProxyFrom(CfgProvider) 216 loadWebhookFrom(CfgProvider) 217 loadMigrationsFrom(CfgProvider) 218 loadIndexerFrom(CfgProvider) 219 loadTaskFrom(CfgProvider) 220 LoadQueueSettings() 221 loadProjectFrom(CfgProvider) 222 loadMimeTypeMapFrom(CfgProvider) 223 loadFederationFrom(CfgProvider) 224 } 225 226 // LoadSettingsForInstall initializes the settings for install 227 func LoadSettingsForInstall() { 228 loadDBSetting(CfgProvider) 229 loadServiceFrom(CfgProvider) 230 loadMailerFrom(CfgProvider) 231 } 232 233 var configuredPaths = make(map[string]string) 234 235 func checkOverlappedPath(name, path string) { 236 // TODO: some paths shouldn't overlap (storage.xxx.path), while some could (data path is the base path for storage path) 237 if targetName, ok := configuredPaths[path]; ok && targetName != name { 238 LogStartupProblem(1, log.ERROR, "Configured path %q is used by %q and %q at the same time. The paths must be unique to prevent data loss.", path, targetName, name) 239 } 240 configuredPaths[path] = name 241 }