|
@@ -2,16 +2,14 @@
|
|
|
// Use of this source code is governed by a MIT-style
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
-package setting
|
|
|
+package conf
|
|
|
|
|
|
import (
|
|
|
"net/mail"
|
|
|
"net/url"
|
|
|
"os"
|
|
|
- "os/exec"
|
|
|
"path"
|
|
|
"path/filepath"
|
|
|
- "runtime"
|
|
|
"strconv"
|
|
|
"strings"
|
|
|
"time"
|
|
@@ -21,83 +19,325 @@ import (
|
|
|
"github.com/go-macaron/session"
|
|
|
_ "github.com/go-macaron/session/redis"
|
|
|
"github.com/mcuadros/go-version"
|
|
|
- "github.com/unknwon/com"
|
|
|
+ "github.com/pkg/errors"
|
|
|
"gopkg.in/ini.v1"
|
|
|
log "unknwon.dev/clog/v2"
|
|
|
|
|
|
"github.com/gogs/go-libravatar"
|
|
|
|
|
|
"gogs.io/gogs/internal/assets/conf"
|
|
|
- "gogs.io/gogs/internal/process"
|
|
|
+ "gogs.io/gogs/internal/osutil"
|
|
|
"gogs.io/gogs/internal/user"
|
|
|
)
|
|
|
|
|
|
-type Scheme string
|
|
|
+func init() {
|
|
|
+ // Initialize the primary logger until logging service is up.
|
|
|
+ err := log.NewConsole()
|
|
|
+ if err != nil {
|
|
|
+ panic("init console logger: " + err.Error())
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
-const (
|
|
|
- SCHEME_HTTP Scheme = "http"
|
|
|
- SCHEME_HTTPS Scheme = "https"
|
|
|
- SCHEME_FCGI Scheme = "fcgi"
|
|
|
- SCHEME_UNIX_SOCKET Scheme = "unix"
|
|
|
-)
|
|
|
+// Asset is a wrapper for getting conf assets.
|
|
|
+func Asset(name string) ([]byte, error) {
|
|
|
+ return conf.Asset(name)
|
|
|
+}
|
|
|
|
|
|
-type LandingPage string
|
|
|
+// AssetDir is a wrapper for getting conf assets.
|
|
|
+func AssetDir(name string) ([]string, error) {
|
|
|
+ return conf.AssetDir(name)
|
|
|
+}
|
|
|
|
|
|
-const (
|
|
|
- LANDING_PAGE_HOME LandingPage = "/"
|
|
|
- LANDING_PAGE_EXPLORE LandingPage = "/explore"
|
|
|
-)
|
|
|
+// MustAsset is a wrapper for getting conf assets.
|
|
|
+func MustAsset(name string) []byte {
|
|
|
+ return conf.MustAsset(name)
|
|
|
+}
|
|
|
|
|
|
-var (
|
|
|
- // Build information should only be set by -ldflags.
|
|
|
- BuildTime string
|
|
|
- BuildCommit string
|
|
|
-
|
|
|
- // App settings
|
|
|
- AppVersion string
|
|
|
- AppName string
|
|
|
- AppURL string
|
|
|
- AppSubURL string
|
|
|
- AppSubURLDepth int // Number of slashes
|
|
|
- AppPath string
|
|
|
- AppDataPath string
|
|
|
- HostAddress string // AppURL without protocol and slashes
|
|
|
-
|
|
|
- // Server settings
|
|
|
- Protocol Scheme
|
|
|
- Domain string
|
|
|
- HTTPAddr string
|
|
|
- HTTPPort string
|
|
|
- LocalURL string
|
|
|
- OfflineMode bool
|
|
|
- DisableRouterLog bool
|
|
|
- CertFile string
|
|
|
- KeyFile string
|
|
|
- TLSMinVersion string
|
|
|
- LoadAssetsFromDisk bool
|
|
|
- StaticRootPath string
|
|
|
- EnableGzip bool
|
|
|
- LandingPageURL LandingPage
|
|
|
- UnixSocketPermission uint32
|
|
|
+// File is the configuration object.
|
|
|
+var File *ini.File
|
|
|
+
|
|
|
+// Init initializes configuration from conf assets and given custom configuration file.
|
|
|
+// If `customConf` is empty, it falls back to default location, i.e. "<WORK DIR>/custom".
|
|
|
+// It is safe to call this function multiple times with desired `customConf`, but it is
|
|
|
+// not concurrent safe.
|
|
|
+//
|
|
|
+// ⚠️ WARNING: Do not print anything in this function other than wanrings.
|
|
|
+func Init(customConf string) error {
|
|
|
+ var err error
|
|
|
+ File, err = ini.LoadSources(ini.LoadOptions{
|
|
|
+ IgnoreInlineComment: true,
|
|
|
+ }, conf.MustAsset("conf/app.ini"))
|
|
|
+ if err != nil {
|
|
|
+ return errors.Wrap(err, "parse 'conf/app.ini'")
|
|
|
+ }
|
|
|
+ File.NameMapper = ini.SnackCase
|
|
|
|
|
|
- HTTP struct {
|
|
|
- AccessControlAllowOrigin string
|
|
|
+ customConf, err = filepath.Abs(customConf)
|
|
|
+ if err != nil {
|
|
|
+ return errors.Wrap(err, "get absolute path")
|
|
|
+ }
|
|
|
+ if customConf == "" {
|
|
|
+ customConf = filepath.Join(CustomDir(), "conf/app.ini")
|
|
|
+ }
|
|
|
+ CustomConf = customConf
|
|
|
+
|
|
|
+ if osutil.IsFile(customConf) {
|
|
|
+ if err = File.Append(customConf); err != nil {
|
|
|
+ return errors.Wrapf(err, "append %q", customConf)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ log.Warn("Custom config %q not found. Ignore this warning if you're running for the first time", customConf)
|
|
|
+ }
|
|
|
+
|
|
|
+ if err = File.Section(ini.DefaultSection).MapTo(&App); err != nil {
|
|
|
+ return errors.Wrap(err, "mapping default section")
|
|
|
+ }
|
|
|
+
|
|
|
+ // ***************************
|
|
|
+ // ----- Server settings -----
|
|
|
+ // ***************************
|
|
|
+
|
|
|
+ if err = File.Section("server").MapTo(&Server); err != nil {
|
|
|
+ return errors.Wrap(err, "mapping [server] section")
|
|
|
+ }
|
|
|
+
|
|
|
+ if !strings.HasSuffix(Server.ExternalURL, "/") {
|
|
|
+ Server.ExternalURL += "/"
|
|
|
+ }
|
|
|
+ Server.URL, err = url.Parse(Server.ExternalURL)
|
|
|
+ if err != nil {
|
|
|
+ return errors.Wrapf(err, "parse '[server] EXTERNAL_URL' %q", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // Subpath should start with '/' and end without '/', i.e. '/{subpath}'.
|
|
|
+ Server.Subpath = strings.TrimRight(Server.URL.Path, "/")
|
|
|
+ Server.SubpathDepth = strings.Count(Server.Subpath, "/")
|
|
|
+
|
|
|
+ unixSocketMode, err := strconv.ParseUint(Server.UnixSocketPermission, 8, 32)
|
|
|
+ if err != nil {
|
|
|
+ return errors.Wrapf(err, "parse '[server] UNIX_SOCKET_PERMISSION' %q", Server.UnixSocketPermission)
|
|
|
+ }
|
|
|
+ if unixSocketMode > 0777 {
|
|
|
+ unixSocketMode = 0666
|
|
|
+ }
|
|
|
+ Server.UnixSocketMode = os.FileMode(unixSocketMode)
|
|
|
+
|
|
|
+ // ************************
|
|
|
+ // ----- SSH settings -----
|
|
|
+ // ************************
|
|
|
+
|
|
|
+ if err = File.Section("server").MapTo(&SSH); err != nil {
|
|
|
+ return errors.Wrap(err, "mapping SSH settings from [server] section")
|
|
|
+ }
|
|
|
+
|
|
|
+ if !SSH.Disabled {
|
|
|
+ if !SSH.StartBuiltinServer {
|
|
|
+ SSH.RootPath = filepath.Join(HomeDir(), ".ssh")
|
|
|
+ SSH.KeyTestPath = os.TempDir()
|
|
|
+
|
|
|
+ if err := os.MkdirAll(SSH.RootPath, 0700); err != nil {
|
|
|
+ return errors.Wrap(err, "create SSH root directory")
|
|
|
+ } else if err = os.MkdirAll(SSH.KeyTestPath, 0644); err != nil {
|
|
|
+ return errors.Wrap(err, "create SSH key test directory")
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ SSH.RewriteAuthorizedKeysAtStart = false
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check if server is eligible for minimum key size check when user choose to enable.
|
|
|
+ // Windows server and OpenSSH version lower than 5.1 are forced to be disabled because
|
|
|
+ // the "ssh-keygen" in Windows does not print key type.
|
|
|
+ // See https://github.com/gogs/gogs/issues/4507.
|
|
|
+ if SSH.MinimumKeySizeCheck {
|
|
|
+ sshVersion, err := openSSHVersion()
|
|
|
+ if err != nil {
|
|
|
+ return errors.Wrap(err, "get OpenSSH version")
|
|
|
+ }
|
|
|
+
|
|
|
+ if IsWindowsRuntime() || version.Compare(sshVersion, "5.1", "<") {
|
|
|
+ log.Warn(`SSH minimum key size check is forced to be disabled because server is not eligible:
|
|
|
+ 1. Windows server
|
|
|
+ 2. OpenSSH version is lower than 5.1`)
|
|
|
+ } else {
|
|
|
+ SSH.MinimumKeySizes = map[string]int{}
|
|
|
+ for _, key := range File.Section("ssh.minimum_key_sizes").Keys() {
|
|
|
+ if key.MustInt() != -1 {
|
|
|
+ SSH.MinimumKeySizes[strings.ToLower(key.Name())] = key.MustInt()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- SSH struct {
|
|
|
- Disabled bool `ini:"DISABLE_SSH"`
|
|
|
- StartBuiltinServer bool `ini:"START_SSH_SERVER"`
|
|
|
- Domain string `ini:"SSH_DOMAIN"`
|
|
|
- Port int `ini:"SSH_PORT"`
|
|
|
- ListenHost string `ini:"SSH_LISTEN_HOST"`
|
|
|
- ListenPort int `ini:"SSH_LISTEN_PORT"`
|
|
|
- RootPath string `ini:"SSH_ROOT_PATH"`
|
|
|
- RewriteAuthorizedKeysAtStart bool `ini:"REWRITE_AUTHORIZED_KEYS_AT_START"`
|
|
|
- ServerCiphers []string `ini:"SSH_SERVER_CIPHERS"`
|
|
|
- KeyTestPath string `ini:"SSH_KEY_TEST_PATH"`
|
|
|
- KeygenPath string `ini:"SSH_KEYGEN_PATH"`
|
|
|
- MinimumKeySizeCheck bool `ini:"MINIMUM_KEY_SIZE_CHECK"`
|
|
|
- MinimumKeySizes map[string]int `ini:"-"`
|
|
|
+ transferDeprecated()
|
|
|
+
|
|
|
+ // TODO
|
|
|
+
|
|
|
+ sec := File.Section("security")
|
|
|
+ InstallLock = sec.Key("INSTALL_LOCK").MustBool()
|
|
|
+ SecretKey = sec.Key("SECRET_KEY").String()
|
|
|
+ LoginRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt()
|
|
|
+ CookieUserName = sec.Key("COOKIE_USERNAME").String()
|
|
|
+ CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").String()
|
|
|
+ CookieSecure = sec.Key("COOKIE_SECURE").MustBool(false)
|
|
|
+ ReverseProxyAuthUser = sec.Key("REVERSE_PROXY_AUTHENTICATION_USER").MustString("X-WEBAUTH-USER")
|
|
|
+ EnableLoginStatusCookie = sec.Key("ENABLE_LOGIN_STATUS_COOKIE").MustBool(false)
|
|
|
+ LoginStatusCookieName = sec.Key("LOGIN_STATUS_COOKIE_NAME").MustString("login_status")
|
|
|
+
|
|
|
+ // Does not check run user when the install lock is off.
|
|
|
+ if InstallLock {
|
|
|
+ currentUser, match := IsRunUserMatchCurrentUser(App.RunUser)
|
|
|
+ if !match {
|
|
|
+ log.Fatal("The user configured to run Gogs is %q, but the current user is %q", App.RunUser, currentUser)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ sec = File.Section("attachment")
|
|
|
+ AttachmentPath = sec.Key("PATH").MustString(filepath.Join(Server.AppDataPath, "attachments"))
|
|
|
+ if !filepath.IsAbs(AttachmentPath) {
|
|
|
+ AttachmentPath = path.Join(workDir, AttachmentPath)
|
|
|
+ }
|
|
|
+ AttachmentAllowedTypes = strings.Replace(sec.Key("ALLOWED_TYPES").MustString("image/jpeg,image/png"), "|", ",", -1)
|
|
|
+ AttachmentMaxSize = sec.Key("MAX_SIZE").MustInt64(4)
|
|
|
+ AttachmentMaxFiles = sec.Key("MAX_FILES").MustInt(5)
|
|
|
+ AttachmentEnabled = sec.Key("ENABLED").MustBool(true)
|
|
|
+
|
|
|
+ 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,
|
|
|
+ }[File.Section("time").Key("FORMAT").MustString("RFC1123")]
|
|
|
+
|
|
|
+ // Determine and create root git repository path.
|
|
|
+ sec = File.Section("repository")
|
|
|
+ RepoRootPath = sec.Key("ROOT").MustString(filepath.Join(HomeDir(), "gogs-repositories"))
|
|
|
+ if !filepath.IsAbs(RepoRootPath) {
|
|
|
+ RepoRootPath = path.Join(workDir, RepoRootPath)
|
|
|
+ } else {
|
|
|
+ RepoRootPath = path.Clean(RepoRootPath)
|
|
|
+ }
|
|
|
+ ScriptType = sec.Key("SCRIPT_TYPE").MustString("bash")
|
|
|
+ if err = File.Section("repository").MapTo(&Repository); err != nil {
|
|
|
+ log.Fatal("Failed to map Repository settings: %v", err)
|
|
|
+ } else if err = File.Section("repository.editor").MapTo(&Repository.Editor); err != nil {
|
|
|
+ log.Fatal("Failed to map Repository.Editor settings: %v", err)
|
|
|
+ } else if err = File.Section("repository.upload").MapTo(&Repository.Upload); err != nil {
|
|
|
+ log.Fatal("Failed to map Repository.Upload settings: %v", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ if !filepath.IsAbs(Repository.Upload.TempPath) {
|
|
|
+ Repository.Upload.TempPath = path.Join(workDir, Repository.Upload.TempPath)
|
|
|
+ }
|
|
|
+
|
|
|
+ sec = File.Section("picture")
|
|
|
+ AvatarUploadPath = sec.Key("AVATAR_UPLOAD_PATH").MustString(filepath.Join(Server.AppDataPath, "avatars"))
|
|
|
+ if !filepath.IsAbs(AvatarUploadPath) {
|
|
|
+ AvatarUploadPath = path.Join(workDir, AvatarUploadPath)
|
|
|
+ }
|
|
|
+ RepositoryAvatarUploadPath = sec.Key("REPOSITORY_AVATAR_UPLOAD_PATH").MustString(filepath.Join(Server.AppDataPath, "repo-avatars"))
|
|
|
+ if !filepath.IsAbs(RepositoryAvatarUploadPath) {
|
|
|
+ RepositoryAvatarUploadPath = path.Join(workDir, RepositoryAvatarUploadPath)
|
|
|
+ }
|
|
|
+ switch source := sec.Key("GRAVATAR_SOURCE").MustString("gravatar"); source {
|
|
|
+ case "duoshuo":
|
|
|
+ GravatarSource = "http://gravatar.duoshuo.com/avatar/"
|
|
|
+ case "gravatar":
|
|
|
+ GravatarSource = "https://secure.gravatar.com/avatar/"
|
|
|
+ case "libravatar":
|
|
|
+ GravatarSource = "https://seccdn.libravatar.org/avatar/"
|
|
|
+ default:
|
|
|
+ GravatarSource = source
|
|
|
+ }
|
|
|
+ DisableGravatar = sec.Key("DISABLE_GRAVATAR").MustBool()
|
|
|
+ EnableFederatedAvatar = sec.Key("ENABLE_FEDERATED_AVATAR").MustBool(true)
|
|
|
+ if Server.OfflineMode {
|
|
|
+ DisableGravatar = true
|
|
|
+ EnableFederatedAvatar = false
|
|
|
+ }
|
|
|
+ if DisableGravatar {
|
|
|
+ EnableFederatedAvatar = false
|
|
|
+ }
|
|
|
+
|
|
|
+ if EnableFederatedAvatar {
|
|
|
+ LibravatarService = libravatar.New()
|
|
|
+ parts := strings.Split(GravatarSource, "/")
|
|
|
+ if len(parts) >= 3 {
|
|
|
+ if parts[0] == "https:" {
|
|
|
+ LibravatarService.SetUseHTTPS(true)
|
|
|
+ LibravatarService.SetSecureFallbackHost(parts[2])
|
|
|
+ } else {
|
|
|
+ LibravatarService.SetUseHTTPS(false)
|
|
|
+ LibravatarService.SetFallbackHost(parts[2])
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if err = File.Section("http").MapTo(&HTTP); err != nil {
|
|
|
+ log.Fatal("Failed to map HTTP settings: %v", err)
|
|
|
+ } else if err = File.Section("webhook").MapTo(&Webhook); err != nil {
|
|
|
+ log.Fatal("Failed to map Webhook settings: %v", err)
|
|
|
+ } else if err = File.Section("release.attachment").MapTo(&Release.Attachment); err != nil {
|
|
|
+ log.Fatal("Failed to map Release.Attachment settings: %v", err)
|
|
|
+ } else if err = File.Section("markdown").MapTo(&Markdown); err != nil {
|
|
|
+ log.Fatal("Failed to map Markdown settings: %v", err)
|
|
|
+ } else if err = File.Section("smartypants").MapTo(&Smartypants); err != nil {
|
|
|
+ log.Fatal("Failed to map Smartypants settings: %v", err)
|
|
|
+ } else if err = File.Section("admin").MapTo(&Admin); err != nil {
|
|
|
+ log.Fatal("Failed to map Admin settings: %v", err)
|
|
|
+ } else if err = File.Section("cron").MapTo(&Cron); err != nil {
|
|
|
+ log.Fatal("Failed to map Cron settings: %v", err)
|
|
|
+ } else if err = File.Section("git").MapTo(&Git); err != nil {
|
|
|
+ log.Fatal("Failed to map Git settings: %v", err)
|
|
|
+ } else if err = File.Section("mirror").MapTo(&Mirror); err != nil {
|
|
|
+ log.Fatal("Failed to map Mirror settings: %v", err)
|
|
|
+ } else if err = File.Section("api").MapTo(&API); err != nil {
|
|
|
+ log.Fatal("Failed to map API settings: %v", err)
|
|
|
+ } else if err = File.Section("ui").MapTo(&UI); err != nil {
|
|
|
+ log.Fatal("Failed to map UI settings: %v", err)
|
|
|
+ } else if err = File.Section("prometheus").MapTo(&Prometheus); err != nil {
|
|
|
+ log.Fatal("Failed to map Prometheus settings: %v", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ if Mirror.DefaultInterval <= 0 {
|
|
|
+ Mirror.DefaultInterval = 24
|
|
|
+ }
|
|
|
+
|
|
|
+ Langs = File.Section("i18n").Key("LANGS").Strings(",")
|
|
|
+ Names = File.Section("i18n").Key("NAMES").Strings(",")
|
|
|
+ dateLangs = File.Section("i18n.datelang").KeysHash()
|
|
|
+
|
|
|
+ ShowFooterBranding = File.Section("other").Key("SHOW_FOOTER_BRANDING").MustBool()
|
|
|
+ ShowFooterTemplateLoadTime = File.Section("other").Key("SHOW_FOOTER_TEMPLATE_LOAD_TIME").MustBool()
|
|
|
+
|
|
|
+ HasRobotsTxt = osutil.IsFile(path.Join(CustomDir(), "robots.txt"))
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// MustInit panics if configuration initialization failed.
|
|
|
+func MustInit(customConf string) {
|
|
|
+ err := Init(customConf)
|
|
|
+ if err != nil {
|
|
|
+ panic(err)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// TODO
|
|
|
+
|
|
|
+var (
|
|
|
+ HTTP struct {
|
|
|
+ AccessControlAllowOrigin string
|
|
|
}
|
|
|
|
|
|
// Security settings
|
|
@@ -316,12 +556,6 @@ var (
|
|
|
ShowFooterTemplateLoadTime bool
|
|
|
|
|
|
// Global setting objects
|
|
|
- Cfg *ini.File
|
|
|
- CustomPath string // Custom directory path
|
|
|
- CustomConf string
|
|
|
- ProdMode bool
|
|
|
- RunUser string
|
|
|
- IsWindows bool
|
|
|
HasRobotsTxt bool
|
|
|
)
|
|
|
|
|
@@ -334,59 +568,12 @@ func DateLang(lang string) string {
|
|
|
return "en"
|
|
|
}
|
|
|
|
|
|
-// execPath returns the executable path.
|
|
|
-func execPath() (string, error) {
|
|
|
- file, err := exec.LookPath(os.Args[0])
|
|
|
- if err != nil {
|
|
|
- return "", err
|
|
|
- }
|
|
|
- return filepath.Abs(file)
|
|
|
-}
|
|
|
-
|
|
|
-func init() {
|
|
|
- IsWindows = runtime.GOOS == "windows"
|
|
|
-
|
|
|
- err := log.NewConsole()
|
|
|
- if err != nil {
|
|
|
- panic("init console logger: " + err.Error())
|
|
|
- }
|
|
|
-
|
|
|
- AppPath, err = execPath()
|
|
|
- if err != nil {
|
|
|
- log.Fatal("Failed to get executable path: %v", err)
|
|
|
- }
|
|
|
-
|
|
|
- // NOTE: we don't use path.Dir here because it does not handle case
|
|
|
- // which path starts with two "/" in Windows: "//psf/Home/..."
|
|
|
- AppPath = strings.Replace(AppPath, "\\", "/", -1)
|
|
|
-}
|
|
|
-
|
|
|
-// WorkDir returns absolute path of work directory.
|
|
|
-func WorkDir() (string, error) {
|
|
|
- wd := os.Getenv("GOGS_WORK_DIR")
|
|
|
- if len(wd) > 0 {
|
|
|
- return wd, nil
|
|
|
- }
|
|
|
-
|
|
|
- i := strings.LastIndex(AppPath, "/")
|
|
|
- if i == -1 {
|
|
|
- return AppPath, nil
|
|
|
- }
|
|
|
- return AppPath[:i], nil
|
|
|
-}
|
|
|
-
|
|
|
-func forcePathSeparator(path string) {
|
|
|
- if strings.Contains(path, "\\") {
|
|
|
- log.Fatal("Do not use '\\' or '\\\\' in paths, please use '/' in all places")
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
// IsRunUserMatchCurrentUser returns false if configured run user does not match
|
|
|
// actual user that runs the app. The first return value is the actual user name.
|
|
|
// This check is ignored under Windows since SSH remote login is not the main
|
|
|
// method to login on Windows.
|
|
|
func IsRunUserMatchCurrentUser(runUser string) (string, bool) {
|
|
|
- if IsWindows {
|
|
|
+ if IsWindowsRuntime() {
|
|
|
return "", true
|
|
|
}
|
|
|
|
|
@@ -394,351 +581,17 @@ func IsRunUserMatchCurrentUser(runUser string) (string, bool) {
|
|
|
return currentUser, runUser == currentUser
|
|
|
}
|
|
|
|
|
|
-// getOpenSSHVersion parses and returns string representation of OpenSSH version
|
|
|
-// returned by command "ssh -V".
|
|
|
-func getOpenSSHVersion() string {
|
|
|
- // NOTE: Somehow the version is printed to stderr.
|
|
|
- _, stderr, err := process.Exec("setting.getOpenSSHVersion", "ssh", "-V")
|
|
|
- if err != nil {
|
|
|
- log.Fatal("Failed to get OpenSSH version: %v - %s", err, stderr)
|
|
|
- }
|
|
|
-
|
|
|
- // Trim unused information: https://github.com/gogs/gogs/issues/4507#issuecomment-305150441
|
|
|
- version := strings.TrimRight(strings.Fields(stderr)[0], ",1234567890")
|
|
|
- version = strings.TrimSuffix(strings.TrimPrefix(version, "OpenSSH_"), "p")
|
|
|
- return version
|
|
|
-}
|
|
|
-
|
|
|
-// Init initializes configuration by loading from sources.
|
|
|
-// ⚠️ WARNING: Do not print anything in this function other than wanrings or errors.
|
|
|
-func Init() {
|
|
|
- workDir, err := WorkDir()
|
|
|
- if err != nil {
|
|
|
- log.Fatal("Failed to get work directory: %v", err)
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- Cfg, err = ini.LoadSources(ini.LoadOptions{
|
|
|
- IgnoreInlineComment: true,
|
|
|
- }, conf.MustAsset("conf/app.ini"))
|
|
|
- if err != nil {
|
|
|
- log.Fatal("Failed to parse 'conf/app.ini': %v", err)
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- CustomPath = os.Getenv("GOGS_CUSTOM")
|
|
|
- if len(CustomPath) == 0 {
|
|
|
- CustomPath = workDir + "/custom"
|
|
|
- }
|
|
|
-
|
|
|
- if len(CustomConf) == 0 {
|
|
|
- CustomConf = CustomPath + "/conf/app.ini"
|
|
|
- }
|
|
|
-
|
|
|
- if com.IsFile(CustomConf) {
|
|
|
- if err = Cfg.Append(CustomConf); err != nil {
|
|
|
- log.Fatal("Failed to load custom conf %q: %v", CustomConf, err)
|
|
|
- return
|
|
|
- }
|
|
|
- } else {
|
|
|
- log.Warn("Custom config '%s' not found, ignore this warning if you're running the first time", CustomConf)
|
|
|
- }
|
|
|
- Cfg.NameMapper = ini.SnackCase
|
|
|
-
|
|
|
- homeDir, err := com.HomeDir()
|
|
|
- if err != nil {
|
|
|
- log.Fatal("Failed to get home directory: %v", err)
|
|
|
- return
|
|
|
- }
|
|
|
- homeDir = strings.Replace(homeDir, "\\", "/", -1)
|
|
|
-
|
|
|
- LogRootPath = Cfg.Section("log").Key("ROOT_PATH").MustString(path.Join(workDir, "log"))
|
|
|
- forcePathSeparator(LogRootPath)
|
|
|
-
|
|
|
- sec := Cfg.Section("server")
|
|
|
- AppName = Cfg.Section("").Key("APP_NAME").MustString("Gogs")
|
|
|
- AppURL = sec.Key("ROOT_URL").MustString("http://localhost:3000/")
|
|
|
- if AppURL[len(AppURL)-1] != '/' {
|
|
|
- AppURL += "/"
|
|
|
- }
|
|
|
-
|
|
|
- // Check if has app suburl.
|
|
|
- url, err := url.Parse(AppURL)
|
|
|
- if err != nil {
|
|
|
- log.Fatal("Failed to parse ROOT_URL %q: %s", AppURL, err)
|
|
|
- return
|
|
|
- }
|
|
|
- // Suburl should start with '/' and end without '/', such as '/{subpath}'.
|
|
|
- // This value is empty if site does not have sub-url.
|
|
|
- AppSubURL = strings.TrimSuffix(url.Path, "/")
|
|
|
- AppSubURLDepth = strings.Count(AppSubURL, "/")
|
|
|
- HostAddress = url.Host
|
|
|
-
|
|
|
- Protocol = SCHEME_HTTP
|
|
|
- if sec.Key("PROTOCOL").String() == "https" {
|
|
|
- Protocol = SCHEME_HTTPS
|
|
|
- CertFile = sec.Key("CERT_FILE").String()
|
|
|
- KeyFile = sec.Key("KEY_FILE").String()
|
|
|
- TLSMinVersion = sec.Key("TLS_MIN_VERSION").String()
|
|
|
- } else if sec.Key("PROTOCOL").String() == "fcgi" {
|
|
|
- Protocol = SCHEME_FCGI
|
|
|
- } else if sec.Key("PROTOCOL").String() == "unix" {
|
|
|
- Protocol = SCHEME_UNIX_SOCKET
|
|
|
- UnixSocketPermissionRaw := sec.Key("UNIX_SOCKET_PERMISSION").MustString("666")
|
|
|
- UnixSocketPermissionParsed, err := strconv.ParseUint(UnixSocketPermissionRaw, 8, 32)
|
|
|
- if err != nil || UnixSocketPermissionParsed > 0777 {
|
|
|
- log.Fatal("Failed to parse unixSocketPermission %q: %v", UnixSocketPermissionRaw, err)
|
|
|
- return
|
|
|
- }
|
|
|
- UnixSocketPermission = uint32(UnixSocketPermissionParsed)
|
|
|
- }
|
|
|
- Domain = sec.Key("DOMAIN").MustString("localhost")
|
|
|
- HTTPAddr = sec.Key("HTTP_ADDR").MustString("0.0.0.0")
|
|
|
- HTTPPort = sec.Key("HTTP_PORT").MustString("3000")
|
|
|
- LocalURL = sec.Key("LOCAL_ROOT_URL").MustString(string(Protocol) + "://localhost:" + HTTPPort + "/")
|
|
|
- OfflineMode = sec.Key("OFFLINE_MODE").MustBool()
|
|
|
- DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool()
|
|
|
- LoadAssetsFromDisk = sec.Key("LOAD_ASSETS_FROM_DISK").MustBool()
|
|
|
- StaticRootPath = sec.Key("STATIC_ROOT_PATH").MustString(workDir)
|
|
|
- AppDataPath = sec.Key("APP_DATA_PATH").MustString("data")
|
|
|
- EnableGzip = sec.Key("ENABLE_GZIP").MustBool()
|
|
|
-
|
|
|
- switch sec.Key("LANDING_PAGE").MustString("home") {
|
|
|
- case "explore":
|
|
|
- LandingPageURL = LANDING_PAGE_EXPLORE
|
|
|
- default:
|
|
|
- LandingPageURL = LANDING_PAGE_HOME
|
|
|
- }
|
|
|
-
|
|
|
- SSH.RootPath = path.Join(homeDir, ".ssh")
|
|
|
- SSH.RewriteAuthorizedKeysAtStart = sec.Key("REWRITE_AUTHORIZED_KEYS_AT_START").MustBool()
|
|
|
- SSH.ServerCiphers = sec.Key("SSH_SERVER_CIPHERS").Strings(",")
|
|
|
- SSH.KeyTestPath = os.TempDir()
|
|
|
- if err = Cfg.Section("server").MapTo(&SSH); err != nil {
|
|
|
- log.Fatal("Failed to map SSH settings: %v", err)
|
|
|
- return
|
|
|
- }
|
|
|
- if SSH.Disabled {
|
|
|
- SSH.StartBuiltinServer = false
|
|
|
- SSH.MinimumKeySizeCheck = false
|
|
|
- }
|
|
|
-
|
|
|
- if !SSH.Disabled && !SSH.StartBuiltinServer {
|
|
|
- if err := os.MkdirAll(SSH.RootPath, 0700); err != nil {
|
|
|
- log.Fatal("Failed to create '%s': %v", SSH.RootPath, err)
|
|
|
- return
|
|
|
- } else if err = os.MkdirAll(SSH.KeyTestPath, 0644); err != nil {
|
|
|
- log.Fatal("Failed to create '%s': %v", SSH.KeyTestPath, err)
|
|
|
- return
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if SSH.StartBuiltinServer {
|
|
|
- SSH.RewriteAuthorizedKeysAtStart = false
|
|
|
- }
|
|
|
-
|
|
|
- // Check if server is eligible for minimum key size check when user choose to enable.
|
|
|
- // Windows server and OpenSSH version lower than 5.1 (https://gogs.io/gogs/issues/4507)
|
|
|
- // are forced to be disabled because the "ssh-keygen" in Windows does not print key type.
|
|
|
- if SSH.MinimumKeySizeCheck &&
|
|
|
- (IsWindows || version.Compare(getOpenSSHVersion(), "5.1", "<")) {
|
|
|
- SSH.MinimumKeySizeCheck = false
|
|
|
- log.Warn(`SSH minimum key size check is forced to be disabled because server is not eligible:
|
|
|
-1. Windows server
|
|
|
-2. OpenSSH version is lower than 5.1`)
|
|
|
- }
|
|
|
-
|
|
|
- if SSH.MinimumKeySizeCheck {
|
|
|
- SSH.MinimumKeySizes = map[string]int{}
|
|
|
- for _, key := range Cfg.Section("ssh.minimum_key_sizes").Keys() {
|
|
|
- if key.MustInt() != -1 {
|
|
|
- SSH.MinimumKeySizes[strings.ToLower(key.Name())] = key.MustInt()
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- sec = Cfg.Section("security")
|
|
|
- InstallLock = sec.Key("INSTALL_LOCK").MustBool()
|
|
|
- SecretKey = sec.Key("SECRET_KEY").String()
|
|
|
- LoginRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt()
|
|
|
- CookieUserName = sec.Key("COOKIE_USERNAME").String()
|
|
|
- CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").String()
|
|
|
- CookieSecure = sec.Key("COOKIE_SECURE").MustBool(false)
|
|
|
- ReverseProxyAuthUser = sec.Key("REVERSE_PROXY_AUTHENTICATION_USER").MustString("X-WEBAUTH-USER")
|
|
|
- EnableLoginStatusCookie = sec.Key("ENABLE_LOGIN_STATUS_COOKIE").MustBool(false)
|
|
|
- LoginStatusCookieName = sec.Key("LOGIN_STATUS_COOKIE_NAME").MustString("login_status")
|
|
|
-
|
|
|
- sec = Cfg.Section("attachment")
|
|
|
- AttachmentPath = sec.Key("PATH").MustString(path.Join(AppDataPath, "attachments"))
|
|
|
- if !filepath.IsAbs(AttachmentPath) {
|
|
|
- AttachmentPath = path.Join(workDir, AttachmentPath)
|
|
|
- }
|
|
|
- AttachmentAllowedTypes = strings.Replace(sec.Key("ALLOWED_TYPES").MustString("image/jpeg,image/png"), "|", ",", -1)
|
|
|
- AttachmentMaxSize = sec.Key("MAX_SIZE").MustInt64(4)
|
|
|
- AttachmentMaxFiles = sec.Key("MAX_FILES").MustInt(5)
|
|
|
- AttachmentEnabled = sec.Key("ENABLED").MustBool(true)
|
|
|
-
|
|
|
- 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,
|
|
|
- }[Cfg.Section("time").Key("FORMAT").MustString("RFC1123")]
|
|
|
-
|
|
|
- RunUser = Cfg.Section("").Key("RUN_USER").String()
|
|
|
- // Does not check run user when the install lock is off.
|
|
|
- if InstallLock {
|
|
|
- currentUser, match := IsRunUserMatchCurrentUser(RunUser)
|
|
|
- if !match {
|
|
|
- log.Fatal("The user configured to run Gogs is %q, but the current user is %q", RunUser, currentUser)
|
|
|
- return
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- ProdMode = Cfg.Section("").Key("RUN_MODE").String() == "prod"
|
|
|
-
|
|
|
- // Determine and create root git repository path.
|
|
|
- sec = Cfg.Section("repository")
|
|
|
- RepoRootPath = sec.Key("ROOT").MustString(path.Join(homeDir, "gogs-repositories"))
|
|
|
- forcePathSeparator(RepoRootPath)
|
|
|
- if !filepath.IsAbs(RepoRootPath) {
|
|
|
- RepoRootPath = path.Join(workDir, RepoRootPath)
|
|
|
- } else {
|
|
|
- RepoRootPath = path.Clean(RepoRootPath)
|
|
|
- }
|
|
|
- ScriptType = sec.Key("SCRIPT_TYPE").MustString("bash")
|
|
|
- if err = Cfg.Section("repository").MapTo(&Repository); err != nil {
|
|
|
- log.Fatal("Failed to map Repository settings: %v", err)
|
|
|
- return
|
|
|
- } else if err = Cfg.Section("repository.editor").MapTo(&Repository.Editor); err != nil {
|
|
|
- log.Fatal("Failed to map Repository.Editor settings: %v", err)
|
|
|
- return
|
|
|
- } else if err = Cfg.Section("repository.upload").MapTo(&Repository.Upload); err != nil {
|
|
|
- log.Fatal("Failed to map Repository.Upload settings: %v", err)
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- if !filepath.IsAbs(Repository.Upload.TempPath) {
|
|
|
- Repository.Upload.TempPath = path.Join(workDir, Repository.Upload.TempPath)
|
|
|
- }
|
|
|
-
|
|
|
- sec = Cfg.Section("picture")
|
|
|
- AvatarUploadPath = sec.Key("AVATAR_UPLOAD_PATH").MustString(path.Join(AppDataPath, "avatars"))
|
|
|
- forcePathSeparator(AvatarUploadPath)
|
|
|
- if !filepath.IsAbs(AvatarUploadPath) {
|
|
|
- AvatarUploadPath = path.Join(workDir, AvatarUploadPath)
|
|
|
- }
|
|
|
- RepositoryAvatarUploadPath = sec.Key("REPOSITORY_AVATAR_UPLOAD_PATH").MustString(path.Join(AppDataPath, "repo-avatars"))
|
|
|
- forcePathSeparator(RepositoryAvatarUploadPath)
|
|
|
- if !filepath.IsAbs(RepositoryAvatarUploadPath) {
|
|
|
- RepositoryAvatarUploadPath = path.Join(workDir, RepositoryAvatarUploadPath)
|
|
|
- }
|
|
|
- switch source := sec.Key("GRAVATAR_SOURCE").MustString("gravatar"); source {
|
|
|
- case "duoshuo":
|
|
|
- GravatarSource = "http://gravatar.duoshuo.com/avatar/"
|
|
|
- case "gravatar":
|
|
|
- GravatarSource = "https://secure.gravatar.com/avatar/"
|
|
|
- case "libravatar":
|
|
|
- GravatarSource = "https://seccdn.libravatar.org/avatar/"
|
|
|
- default:
|
|
|
- GravatarSource = source
|
|
|
- }
|
|
|
- DisableGravatar = sec.Key("DISABLE_GRAVATAR").MustBool()
|
|
|
- EnableFederatedAvatar = sec.Key("ENABLE_FEDERATED_AVATAR").MustBool(true)
|
|
|
- if OfflineMode {
|
|
|
- DisableGravatar = true
|
|
|
- EnableFederatedAvatar = false
|
|
|
- }
|
|
|
- if DisableGravatar {
|
|
|
- EnableFederatedAvatar = false
|
|
|
- }
|
|
|
-
|
|
|
- if EnableFederatedAvatar {
|
|
|
- LibravatarService = libravatar.New()
|
|
|
- parts := strings.Split(GravatarSource, "/")
|
|
|
- if len(parts) >= 3 {
|
|
|
- if parts[0] == "https:" {
|
|
|
- LibravatarService.SetUseHTTPS(true)
|
|
|
- LibravatarService.SetSecureFallbackHost(parts[2])
|
|
|
- } else {
|
|
|
- LibravatarService.SetUseHTTPS(false)
|
|
|
- LibravatarService.SetFallbackHost(parts[2])
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if err = Cfg.Section("http").MapTo(&HTTP); err != nil {
|
|
|
- log.Fatal("Failed to map HTTP settings: %v", err)
|
|
|
- return
|
|
|
- } else if err = Cfg.Section("webhook").MapTo(&Webhook); err != nil {
|
|
|
- log.Fatal("Failed to map Webhook settings: %v", err)
|
|
|
- return
|
|
|
- } else if err = Cfg.Section("release.attachment").MapTo(&Release.Attachment); err != nil {
|
|
|
- log.Fatal("Failed to map Release.Attachment settings: %v", err)
|
|
|
- return
|
|
|
- } else if err = Cfg.Section("markdown").MapTo(&Markdown); err != nil {
|
|
|
- log.Fatal("Failed to map Markdown settings: %v", err)
|
|
|
- return
|
|
|
- } else if err = Cfg.Section("smartypants").MapTo(&Smartypants); err != nil {
|
|
|
- log.Fatal("Failed to map Smartypants settings: %v", err)
|
|
|
- return
|
|
|
- } else if err = Cfg.Section("admin").MapTo(&Admin); err != nil {
|
|
|
- log.Fatal("Failed to map Admin settings: %v", err)
|
|
|
- return
|
|
|
- } else if err = Cfg.Section("cron").MapTo(&Cron); err != nil {
|
|
|
- log.Fatal("Failed to map Cron settings: %v", err)
|
|
|
- return
|
|
|
- } else if err = Cfg.Section("git").MapTo(&Git); err != nil {
|
|
|
- log.Fatal("Failed to map Git settings: %v", err)
|
|
|
- return
|
|
|
- } else if err = Cfg.Section("mirror").MapTo(&Mirror); err != nil {
|
|
|
- log.Fatal("Failed to map Mirror settings: %v", err)
|
|
|
- return
|
|
|
- } else if err = Cfg.Section("api").MapTo(&API); err != nil {
|
|
|
- log.Fatal("Failed to map API settings: %v", err)
|
|
|
- return
|
|
|
- } else if err = Cfg.Section("ui").MapTo(&UI); err != nil {
|
|
|
- log.Fatal("Failed to map UI settings: %v", err)
|
|
|
- return
|
|
|
- } else if err = Cfg.Section("prometheus").MapTo(&Prometheus); err != nil {
|
|
|
- log.Fatal("Failed to map Prometheus settings: %v", err)
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- if Mirror.DefaultInterval <= 0 {
|
|
|
- Mirror.DefaultInterval = 24
|
|
|
- }
|
|
|
-
|
|
|
- Langs = Cfg.Section("i18n").Key("LANGS").Strings(",")
|
|
|
- Names = Cfg.Section("i18n").Key("NAMES").Strings(",")
|
|
|
- dateLangs = Cfg.Section("i18n.datelang").KeysHash()
|
|
|
-
|
|
|
- ShowFooterBranding = Cfg.Section("other").Key("SHOW_FOOTER_BRANDING").MustBool()
|
|
|
- ShowFooterTemplateLoadTime = Cfg.Section("other").Key("SHOW_FOOTER_TEMPLATE_LOAD_TIME").MustBool()
|
|
|
-
|
|
|
- HasRobotsTxt = com.IsFile(path.Join(CustomPath, "robots.txt"))
|
|
|
-}
|
|
|
-
|
|
|
-// InitLogging initializes the logging infrastructure of the application.
|
|
|
+// InitLogging initializes the logging service of the application.
|
|
|
func InitLogging() {
|
|
|
+ LogRootPath = File.Section("log").Key("ROOT_PATH").MustString(filepath.Join(WorkDir(), "log"))
|
|
|
+
|
|
|
// Because we always create a console logger as the primary logger at init time,
|
|
|
// we need to remove it in case the user doesn't configure to use it after the
|
|
|
- // logging infrastructure is initalized.
|
|
|
+ // logging service is initalized.
|
|
|
hasConsole := false
|
|
|
|
|
|
// Iterate over [log.*] sections to initialize individual logger.
|
|
|
- LogModes = strings.Split(Cfg.Section("log").Key("MODE").MustString("console"), ",")
|
|
|
+ LogModes = strings.Split(File.Section("log").Key("MODE").MustString("console"), ",")
|
|
|
LogConfigs = make([]interface{}, len(LogModes))
|
|
|
levelMappings := map[string]log.Level{
|
|
|
"trace": log.LevelTrace,
|
|
@@ -755,7 +608,7 @@ func InitLogging() {
|
|
|
for i, mode := range LogModes {
|
|
|
mode = strings.ToLower(strings.TrimSpace(mode))
|
|
|
secName := "log." + mode
|
|
|
- sec, err := Cfg.GetSection(secName)
|
|
|
+ sec, err := File.GetSection(secName)
|
|
|
if err != nil {
|
|
|
log.Fatal("Missing configuration section [%s] for %q logger", secName, mode)
|
|
|
return
|
|
@@ -852,7 +705,7 @@ var Service struct {
|
|
|
}
|
|
|
|
|
|
func newService() {
|
|
|
- sec := Cfg.Section("service")
|
|
|
+ sec := File.Section("service")
|
|
|
Service.ActiveCodeLives = sec.Key("ACTIVE_CODE_LIVE_MINUTES").MustInt(180)
|
|
|
Service.ResetPwdCodeLives = sec.Key("RESET_PASSWD_CODE_LIVE_MINUTES").MustInt(180)
|
|
|
Service.DisableRegistration = sec.Key("DISABLE_REGISTRATION").MustBool()
|
|
@@ -864,12 +717,12 @@ func newService() {
|
|
|
}
|
|
|
|
|
|
func newCacheService() {
|
|
|
- CacheAdapter = Cfg.Section("cache").Key("ADAPTER").In("memory", []string{"memory", "redis", "memcache"})
|
|
|
+ CacheAdapter = File.Section("cache").Key("ADAPTER").In("memory", []string{"memory", "redis", "memcache"})
|
|
|
switch CacheAdapter {
|
|
|
case "memory":
|
|
|
- CacheInterval = Cfg.Section("cache").Key("INTERVAL").MustInt(60)
|
|
|
+ CacheInterval = File.Section("cache").Key("INTERVAL").MustInt(60)
|
|
|
case "redis", "memcache":
|
|
|
- CacheConn = strings.Trim(Cfg.Section("cache").Key("HOST").String(), "\" ")
|
|
|
+ CacheConn = strings.Trim(File.Section("cache").Key("HOST").String(), "\" ")
|
|
|
default:
|
|
|
log.Fatal("Unrecognized cache adapter %q", CacheAdapter)
|
|
|
return
|
|
@@ -879,15 +732,15 @@ func newCacheService() {
|
|
|
}
|
|
|
|
|
|
func newSessionService() {
|
|
|
- SessionConfig.Provider = Cfg.Section("session").Key("PROVIDER").In("memory",
|
|
|
+ SessionConfig.Provider = File.Section("session").Key("PROVIDER").In("memory",
|
|
|
[]string{"memory", "file", "redis", "mysql"})
|
|
|
- SessionConfig.ProviderConfig = strings.Trim(Cfg.Section("session").Key("PROVIDER_CONFIG").String(), "\" ")
|
|
|
- SessionConfig.CookieName = Cfg.Section("session").Key("COOKIE_NAME").MustString("i_like_gogs")
|
|
|
- SessionConfig.CookiePath = AppSubURL
|
|
|
- SessionConfig.Secure = Cfg.Section("session").Key("COOKIE_SECURE").MustBool()
|
|
|
- SessionConfig.Gclifetime = Cfg.Section("session").Key("GC_INTERVAL_TIME").MustInt64(3600)
|
|
|
- SessionConfig.Maxlifetime = Cfg.Section("session").Key("SESSION_LIFE_TIME").MustInt64(86400)
|
|
|
- CSRFCookieName = Cfg.Section("session").Key("CSRF_COOKIE_NAME").MustString("_csrf")
|
|
|
+ SessionConfig.ProviderConfig = strings.Trim(File.Section("session").Key("PROVIDER_CONFIG").String(), "\" ")
|
|
|
+ SessionConfig.CookieName = File.Section("session").Key("COOKIE_NAME").MustString("i_like_gogs")
|
|
|
+ SessionConfig.CookiePath = Server.Subpath
|
|
|
+ SessionConfig.Secure = File.Section("session").Key("COOKIE_SECURE").MustBool()
|
|
|
+ SessionConfig.Gclifetime = File.Section("session").Key("GC_INTERVAL_TIME").MustInt64(3600)
|
|
|
+ SessionConfig.Maxlifetime = File.Section("session").Key("SESSION_LIFE_TIME").MustInt64(86400)
|
|
|
+ CSRFCookieName = File.Section("session").Key("CSRF_COOKIE_NAME").MustString("_csrf")
|
|
|
|
|
|
log.Trace("Session service is enabled")
|
|
|
}
|
|
@@ -916,14 +769,14 @@ var (
|
|
|
// newMailService initializes mail service options from configuration.
|
|
|
// No non-error log will be printed in hook mode.
|
|
|
func newMailService() {
|
|
|
- sec := Cfg.Section("mailer")
|
|
|
+ sec := File.Section("mailer")
|
|
|
if !sec.Key("ENABLED").MustBool() {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
MailService = &Mailer{
|
|
|
QueueLength: sec.Key("SEND_BUFFER_LEN").MustInt(100),
|
|
|
- SubjectPrefix: sec.Key("SUBJECT_PREFIX").MustString("[" + AppName + "] "),
|
|
|
+ SubjectPrefix: sec.Key("SUBJECT_PREFIX").MustString("[" + App.BrandName + "] "),
|
|
|
Host: sec.Key("HOST").String(),
|
|
|
User: sec.Key("USER").String(),
|
|
|
Passwd: sec.Key("PASSWD").String(),
|
|
@@ -954,7 +807,7 @@ func newMailService() {
|
|
|
}
|
|
|
|
|
|
func newRegisterMailService() {
|
|
|
- if !Cfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").MustBool() {
|
|
|
+ if !File.Section("service").Key("REGISTER_EMAIL_CONFIRM").MustBool() {
|
|
|
return
|
|
|
} else if MailService == nil {
|
|
|
log.Warn("Email confirmation is not enabled due to the mail service is not available")
|
|
@@ -967,7 +820,7 @@ func newRegisterMailService() {
|
|
|
// newNotifyMailService initializes notification email service options from configuration.
|
|
|
// No non-error log will be printed in hook mode.
|
|
|
func newNotifyMailService() {
|
|
|
- if !Cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").MustBool() {
|
|
|
+ if !File.Section("service").Key("ENABLE_NOTIFY_MAIL").MustBool() {
|
|
|
return
|
|
|
} else if MailService == nil {
|
|
|
log.Warn("Email notification is not enabled due to the mail service is not available")
|