Files
Atay-Makhzan/modules/setting/setting.go
T

1143 lines
36 KiB
Go
Raw Normal View History

2014-04-10 14:20:58 -04:00
// Copyright 2014 The Gogs Authors. All rights reserved.
2017-05-29 09:17:15 +02:00
// Copyright 2017 The Gitea Authors. All rights reserved.
2014-04-10 14:20:58 -04:00
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
2014-05-25 20:11:25 -04:00
package setting
2014-04-10 14:20:58 -04:00
import (
2016-12-26 02:16:37 +01:00
"encoding/base64"
2020-12-23 20:09:54 +01:00
"encoding/json"
2019-04-02 08:48:31 +01:00
"fmt"
"io"
"io/ioutil"
"math"
"net"
"net/url"
2014-04-10 14:20:58 -04:00
"os"
"os/exec"
"path"
"path/filepath"
"runtime"
"strconv"
2014-04-10 14:20:58 -04:00
"strings"
"time"
2014-04-10 14:20:58 -04:00
"code.gitea.io/gitea/modules/generate"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/user"
"code.gitea.io/gitea/modules/util"
2019-01-09 18:22:57 +01:00
shellquote "github.com/kballard/go-shellquote"
2019-08-23 09:40:30 -07:00
"github.com/unknwon/com"
2020-10-11 02:38:09 +02:00
gossh "golang.org/x/crypto/ssh"
2019-01-09 18:22:57 +01:00
ini "gopkg.in/ini.v1"
2014-04-10 14:20:58 -04:00
)
2016-11-27 18:14:25 +08:00
// Scheme describes protocol types
2014-05-25 20:11:25 -04:00
type Scheme string
2014-04-13 18:12:07 -04:00
2016-11-27 18:14:25 +08:00
// enumerates all the scheme types
2014-05-25 20:11:25 -04:00
const (
2016-11-27 18:14:25 +08:00
HTTP Scheme = "http"
HTTPS Scheme = "https"
FCGI Scheme = "fcgi"
2019-12-10 12:23:26 +00:00
FCGIUnix Scheme = "fcgi+unix"
2016-11-27 18:14:25 +08:00
UnixSocket Scheme = "unix"
2014-05-25 20:11:25 -04:00
)
2014-04-10 14:20:58 -04:00
2016-11-27 18:14:25 +08:00
// LandingPage describes the default page
2014-11-24 18:47:59 -05:00
type LandingPage string
2016-11-27 18:14:25 +08:00
// enumerates all the landing page types
2014-11-24 18:47:59 -05:00
const (
LandingPageHome LandingPage = "/"
LandingPageExplore LandingPage = "/explore"
LandingPageOrganizations LandingPage = "/explore/organizations"
LandingPageLogin LandingPage = "/user/login"
2014-11-24 18:47:59 -05:00
)
// enumerates all the types of captchas
const (
ImageCaptcha = "image"
ReCaptcha = "recaptcha"
2020-10-02 22:37:53 -05:00
HCaptcha = "hcaptcha"
)
2016-11-27 18:14:25 +08:00
// settings
2014-04-10 14:20:58 -04:00
var (
2016-11-27 18:14:25 +08:00
// AppVer settings
AppVer string
2017-02-28 01:40:02 +01:00
AppBuiltWith string
AppStartTime time.Time
AppName string
2016-11-27 18:14:25 +08:00
AppURL string
AppSubURL string
AppSubURLDepth int // Number of slashes
AppPath string
2016-03-09 22:53:42 -03:00
AppDataPath string
AppWorkPath string
2014-05-25 20:11:25 -04:00
// Server settings
Protocol Scheme
Domain string
2016-11-27 18:14:25 +08:00
HTTPAddr string
HTTPPort string
LocalURL string
RedirectOtherPort bool
PortToRedirect string
OfflineMode bool
2016-11-27 18:14:25 +08:00
CertFile string
KeyFile string
StaticRootPath string
StaticCacheTime time.Duration
EnableGzip bool
2016-08-17 16:10:07 -07:00
LandingPageURL LandingPage
UnixSocketPermission uint32
EnablePprof bool
PprofDataPath string
2018-08-21 09:56:50 -04:00
EnableLetsEncrypt bool
LetsEncryptTOS bool
LetsEncryptDirectory string
LetsEncryptEmail string
GracefulRestartable bool
GracefulHammerTime time.Duration
StartupTimeout time.Duration
StaticURLPrefix string
2020-12-23 20:09:54 +01:00
AbsoluteAssetURL string
2014-05-25 20:11:25 -04:00
2016-12-29 04:51:15 -06:00
SSH = struct {
2020-10-11 02:38:09 +02:00
Disabled bool `ini:"DISABLE_SSH"`
StartBuiltinServer bool `ini:"START_SSH_SERVER"`
BuiltinServerUser string `ini:"BUILTIN_SSH_SERVER_USER"`
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"`
ServerCiphers []string `ini:"SSH_SERVER_CIPHERS"`
ServerKeyExchanges []string `ini:"SSH_SERVER_KEY_EXCHANGES"`
ServerMACs []string `ini:"SSH_SERVER_MACS"`
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"`
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:"-"`
2016-12-29 04:51:15 -06:00
}{
2020-10-09 07:52:57 +01:00
Disabled: false,
StartBuiltinServer: false,
Domain: "",
Port: 22,
ServerCiphers: []string{"aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", "arcfour256", "arcfour128"},
ServerKeyExchanges: []string{"diffie-hellman-group1-sha1", "diffie-hellman-group14-sha1", "ecdh-sha2-nistp256", "ecdh-sha2-nistp384", "ecdh-sha2-nistp521", "curve25519-sha256@libssh.org"},
ServerMACs: []string{"hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha1", "hmac-sha1-96"},
KeygenPath: "ssh-keygen",
MinimumKeySizeCheck: true,
MinimumKeySizes: map[string]int{"ed25519": 256, "ed25519-sk": 256, "ecdsa": 256, "ecdsa-sk": 256, "rsa": 2048},
2016-02-27 20:48:39 -05:00
}
// Security settings
InstallLock bool
SecretKey string
LogInRememberDays int
CookieUserName string
CookieRememberName string
ReverseProxyAuthUser string
ReverseProxyAuthEmail string
MinPasswordLength int
ImportLocalPaths bool
DisableGitHooks bool
2021-02-11 18:34:34 +01:00
DisableWebhooks bool
OnlyAllowPushIfGiteaEnvironmentSet bool
PasswordComplexity []string
PasswordHashAlgo string
PasswordCheckPwn bool
2014-04-10 14:20:58 -04:00
// UI settings
2016-12-23 15:18:05 +08:00
UI = struct {
ExplorePagingNum int
IssuePagingNum int
RepoSearchPagingNum int
MembersPagingNum int
FeedMaxCommitNum int
FeedPagingNum int
GraphMaxCommitNum int
CodeCommentLines int
ReactionMaxUserNum int
ThemeColorMetaTag string
MaxDisplayFileSize int64
ShowUserEmail bool
DefaultShowFullName bool
DefaultTheme string
Themes []string
2019-12-01 23:57:24 +01:00
Reactions []string
2019-12-07 23:04:19 +01:00
ReactionsMap map[string]bool
SearchRepoDescription bool
2019-11-21 21:06:23 +01:00
UseServiceWorker bool
2016-07-24 00:23:54 +08:00
2020-04-24 04:57:38 +01:00
Notification struct {
2020-05-07 22:49:00 +01:00
MinTimeout time.Duration
TimeoutStep time.Duration
MaxTimeout time.Duration
EventSourceUpdateTime time.Duration
2020-04-24 04:57:38 +01:00
} `ini:"ui.notification"`
SVG struct {
Enabled bool `ini:"ENABLE_RENDER"`
} `ini:"ui.svg"`
2016-07-24 00:23:54 +08:00
Admin struct {
UserPagingNum int
RepoPagingNum int
NoticePagingNum int
OrgPagingNum int
} `ini:"ui.admin"`
User struct {
RepoPagingNum int
} `ini:"ui.user"`
2017-04-01 03:03:01 +02:00
Meta struct {
Author string
Description string
Keywords string
} `ini:"ui.meta"`
2016-12-23 15:18:05 +08:00
}{
2017-10-26 23:10:54 -07:00
ExplorePagingNum: 20,
IssuePagingNum: 10,
RepoSearchPagingNum: 10,
MembersPagingNum: 20,
2017-10-26 23:10:54 -07:00
FeedMaxCommitNum: 5,
FeedPagingNum: 20,
GraphMaxCommitNum: 100,
CodeCommentLines: 4,
ReactionMaxUserNum: 10,
2017-10-26 23:10:54 -07:00
ThemeColorMetaTag: `#6cc644`,
MaxDisplayFileSize: 8388608,
DefaultTheme: `gitea`,
2019-01-09 18:22:57 +01:00
Themes: []string{`gitea`, `arc-green`},
2019-12-01 23:57:24 +01:00
Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`},
2020-04-24 04:57:38 +01:00
Notification: struct {
2020-05-07 22:49:00 +01:00
MinTimeout time.Duration
TimeoutStep time.Duration
MaxTimeout time.Duration
EventSourceUpdateTime time.Duration
2020-04-24 04:57:38 +01:00
}{
2020-05-07 22:49:00 +01:00
MinTimeout: 10 * time.Second,
TimeoutStep: 10 * time.Second,
MaxTimeout: 60 * time.Second,
EventSourceUpdateTime: 10 * time.Second,
2020-04-24 04:57:38 +01:00
},
SVG: struct {
Enabled bool `ini:"ENABLE_RENDER"`
}{
Enabled: true,
},
2016-12-23 15:18:05 +08:00
Admin: struct {
UserPagingNum int
RepoPagingNum int
NoticePagingNum int
OrgPagingNum int
}{
UserPagingNum: 50,
RepoPagingNum: 50,
NoticePagingNum: 25,
OrgPagingNum: 50,
},
User: struct {
RepoPagingNum int
}{
RepoPagingNum: 15,
},
2017-04-01 03:03:01 +02:00
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",
},
2016-07-24 00:23:54 +08:00
}
2014-04-10 14:20:58 -04:00
2017-03-14 20:52:01 -04:00
// Markdown settings
2016-12-23 15:18:05 +08:00
Markdown = struct {
EnableHardLineBreakInComments bool
EnableHardLineBreakInDocuments bool
CustomURLSchemes []string `ini:"CUSTOM_URL_SCHEMES"`
FileExtensions []string
2016-12-23 15:18:05 +08:00
}{
EnableHardLineBreakInComments: true,
EnableHardLineBreakInDocuments: false,
FileExtensions: strings.Split(".md,.markdown,.mdown,.mkd", ","),
}
// Admin settings
Admin struct {
DisableRegularOrgCreation bool
DefaultEmailNotification string
}
// Log settings
LogLevel string
2019-04-02 08:48:31 +01:00
StacktraceLogLevel string
LogRootPath string
2019-04-02 08:48:31 +01:00
DisableRouterLog bool
RouterLogLevel log.Level
RouterLogMode string
EnableAccessLog bool
AccessLogTemplate string
EnableXORMLog bool
2014-04-10 14:20:58 -04:00
// Time settings
TimeFormat string
// UILocation is the location on the UI, so that we can display the time on UI.
DefaultUILocation = time.Local
2019-07-12 06:57:31 -07:00
CSRFCookieName = "_csrf"
CSRFCookieHTTPOnly = true
2014-04-10 14:20:58 -04:00
2020-12-23 20:09:54 +01:00
ManifestData string
2020-12-22 12:13:50 +01:00
2016-08-09 23:58:15 -07:00
// Mirror settings
Mirror struct {
DefaultInterval time.Duration
MinInterval time.Duration
}
// API settings
2016-12-23 15:18:05 +08:00
API = struct {
EnableSwagger bool
2019-06-12 16:07:24 -05:00
SwaggerURL string
MaxResponseItems int
DefaultPagingNum int
DefaultGitTreesPerPage int
DefaultMaxBlobSize int64
2016-12-23 15:18:05 +08:00
}{
EnableSwagger: true,
2019-06-12 16:07:24 -05:00
SwaggerURL: "",
MaxResponseItems: 50,
DefaultPagingNum: 30,
DefaultGitTreesPerPage: 1000,
DefaultMaxBlobSize: 10485760,
}
2019-03-08 17:42:50 +01:00
OAuth2 = struct {
Enable bool
AccessTokenExpirationTime int64
RefreshTokenExpirationTime int64
InvalidateRefreshTokens bool
2019-03-08 17:42:50 +01:00
JWTSecretBytes []byte `ini:"-"`
JWTSecretBase64 string `ini:"JWT_SECRET"`
MaxTokenLength int
2019-03-08 17:42:50 +01:00
}{
Enable: true,
AccessTokenExpirationTime: 3600,
RefreshTokenExpirationTime: 730,
InvalidateRefreshTokens: false,
MaxTokenLength: math.MaxInt16,
2019-03-08 17:42:50 +01:00
}
2018-05-19 16:12:37 +02:00
U2F = struct {
AppID string
TrustedFacets []string
}{}
2018-11-05 06:20:00 +03:00
// Metrics settings
Metrics = struct {
Enabled bool
Token string
}{
Enabled: false,
Token: "",
}
// I18n settings
Langs []string
Names []string
2014-09-17 14:22:51 -04:00
2017-03-14 20:52:01 -04:00
// Highlight settings are loaded in modules/template/highlight.go
// Other settings
ShowFooterBranding bool
ShowFooterVersion bool
ShowFooterTemplateLoadTime bool
// Global setting objects
Cfg *ini.File
CustomPath string // Custom directory path
CustomConf string
PIDFile = "/run/gitea.pid"
WritePIDFile bool
RunMode string
RunUser string
IsWindows bool
HasRobotsTxt bool
InternalToken string // internal access token
// UILocation is the location on the UI, so that we can display the time on UI.
// Currently only show the default time.Local, it could be added to app.ini after UI is ready
UILocation = time.Local
2014-04-10 14:20:58 -04:00
)
// IsProd if it's a production mode
func IsProd() bool {
return strings.EqualFold(RunMode, "prod")
}
func getAppPath() (string, error) {
var appPath string
var err error
if IsWindows && filepath.IsAbs(os.Args[0]) {
appPath = filepath.Clean(os.Args[0])
} else {
appPath, err = exec.LookPath(os.Args[0])
}
2014-05-25 20:11:25 -04:00
if err != nil {
return "", err
}
appPath, err = filepath.Abs(appPath)
if err != nil {
return "", err
}
// Note: we don't use path.Dir here because it does not handle case
// which path starts with two "/" in Windows: "//psf/Home/..."
return strings.ReplaceAll(appPath, "\\", "/"), err
}
func getWorkPath(appPath string) string {
workPath := AppWorkPath
if giteaWorkPath, ok := os.LookupEnv("GITEA_WORK_DIR"); ok {
workPath = giteaWorkPath
}
if len(workPath) == 0 {
i := strings.LastIndex(appPath, "/")
if i == -1 {
workPath = appPath
} else {
workPath = appPath[:i]
}
}
return strings.ReplaceAll(workPath, "\\", "/")
}
func init() {
IsWindows = runtime.GOOS == "windows"
2019-04-02 08:48:31 +01:00
// We can rely on log.CanColorStdout being set properly because modules/log/console_windows.go comes before modules/setting/setting.go lexicographically
log.NewLogger(0, "console", "console", fmt.Sprintf(`{"level": "trace", "colorize": %t, "stacktraceLevel": "none"}`, log.CanColorStdout))
var err error
if AppPath, err = getAppPath(); err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("Failed to get app path: %v", err)
2014-05-25 20:11:25 -04:00
}
AppWorkPath = getWorkPath(AppPath)
2014-05-25 20:11:25 -04:00
}
func forcePathSeparator(path string) {
if strings.Contains(path, "\\") {
2019-04-02 08:48:31 +01:00
log.Fatal("Do not use '\\' or '\\\\' in paths, instead, please use '/' in all places")
}
}
2016-08-09 17:41:18 -07:00
// 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 || SSH.StartBuiltinServer {
2016-08-09 17:41:18 -07:00
return "", true
}
currentUser := user.CurrentUsername()
return currentUser, runUser == currentUser
}
2017-01-09 19:54:57 +08:00
func createPIDFile(pidPath string) {
currentPid := os.Getpid()
if err := os.MkdirAll(filepath.Dir(pidPath), os.ModePerm); err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("Failed to create PID folder: %v", err)
2017-01-09 19:54:57 +08:00
}
file, err := os.Create(pidPath)
if err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("Failed to create PID file: %v", err)
2017-01-09 19:54:57 +08:00
}
defer file.Close()
if _, err := file.WriteString(strconv.FormatInt(int64(currentPid), 10)); err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("Failed to write PID information: %v", err)
2017-01-09 19:54:57 +08:00
}
}
// SetCustomPathAndConf will set CustomPath and CustomConf with reference to the
// GITEA_CUSTOM environment variable and with provided overrides before stepping
// back to the default
2019-05-14 16:20:35 +01:00
func SetCustomPathAndConf(providedCustom, providedConf, providedWorkPath string) {
if len(providedWorkPath) != 0 {
AppWorkPath = filepath.ToSlash(providedWorkPath)
}
if giteaCustom, ok := os.LookupEnv("GITEA_CUSTOM"); ok {
CustomPath = giteaCustom
}
if len(providedCustom) != 0 {
CustomPath = providedCustom
}
2014-05-25 20:11:25 -04:00
if len(CustomPath) == 0 {
CustomPath = path.Join(AppWorkPath, "custom")
} else if !filepath.IsAbs(CustomPath) {
CustomPath = path.Join(AppWorkPath, CustomPath)
2014-05-25 20:11:25 -04:00
}
if len(providedConf) != 0 {
CustomConf = providedConf
2017-01-09 19:54:57 +08:00
}
if len(CustomConf) == 0 {
CustomConf = path.Join(CustomPath, "conf/app.ini")
} else if !filepath.IsAbs(CustomConf) {
CustomConf = path.Join(CustomPath, CustomConf)
log.Warn("Using 'custom' directory as relative origin for configuration file: '%s'", CustomConf)
}
}
// NewContext initializes configuration context.
// NOTE: do not print any log except error.
func NewContext() {
Cfg = ini.Empty()
if WritePIDFile && len(PIDFile) > 0 {
createPIDFile(PIDFile)
}
isFile, err := util.IsFile(CustomConf)
if err != nil {
log.Error("Unable to check if %s is a file. Error: %v", CustomConf, err)
}
if isFile {
if err := Cfg.Append(CustomConf); err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("Failed to load custom conf '%s': %v", CustomConf, err)
2014-05-25 20:11:25 -04:00
}
} else {
2015-12-19 21:43:32 -05:00
log.Warn("Custom config '%s' not found, ignore this if you're running first time", CustomConf)
2014-05-25 20:11:25 -04:00
}
2019-10-15 15:45:39 +00:00
Cfg.NameMapper = ini.SnackCase
2014-05-25 20:11:25 -04:00
2015-12-19 21:43:32 -05:00
homeDir, err := com.HomeDir()
if err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("Failed to get home directory: %v", err)
2015-12-19 21:43:32 -05:00
}
homeDir = strings.ReplaceAll(homeDir, "\\", "/")
2015-12-19 21:43:32 -05:00
2019-04-02 08:48:31 +01:00
LogLevel = getLogLevel(Cfg.Section("log"), "LEVEL", "Info")
StacktraceLogLevel = getStacktraceLogLevel(Cfg.Section("log"), "STACKTRACE_LEVEL", "None")
LogRootPath = Cfg.Section("log").Key("ROOT_PATH").MustString(path.Join(AppWorkPath, "log"))
forcePathSeparator(LogRootPath)
2019-04-02 08:48:31 +01:00
RouterLogLevel = log.FromString(Cfg.Section("log").Key("ROUTER_LOG_LEVEL").MustString("Info"))
2014-12-31 18:37:29 +08:00
sec := Cfg.Section("server")
AppName = Cfg.Section("").Key("APP_NAME").MustString("Gitea: Git with a cup of tea")
2014-05-25 20:11:25 -04:00
Protocol = HTTP
2019-06-12 21:41:28 +02:00
switch sec.Key("PROTOCOL").String() {
case "https":
2014-05-25 20:11:25 -04:00
Protocol = HTTPS
2014-12-31 18:37:29 +08:00
CertFile = sec.Key("CERT_FILE").String()
KeyFile = sec.Key("KEY_FILE").String()
if !filepath.IsAbs(CertFile) && len(CertFile) > 0 {
CertFile = filepath.Join(CustomPath, CertFile)
}
if !filepath.IsAbs(KeyFile) && len(KeyFile) > 0 {
KeyFile = filepath.Join(CustomPath, KeyFile)
}
2019-06-12 21:41:28 +02:00
case "fcgi":
2014-11-03 20:46:53 -05:00
Protocol = FCGI
2019-12-10 12:23:26 +00:00
case "fcgi+unix":
Protocol = FCGIUnix
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: %s", UnixSocketPermissionRaw)
}
UnixSocketPermission = uint32(UnixSocketPermissionParsed)
2019-06-12 21:41:28 +02:00
case "unix":
2016-11-27 18:14:25 +08:00
Protocol = UnixSocket
2016-08-11 14:55:10 -07:00
UnixSocketPermissionRaw := sec.Key("UNIX_SOCKET_PERMISSION").MustString("666")
UnixSocketPermissionParsed, err := strconv.ParseUint(UnixSocketPermissionRaw, 8, 32)
if err != nil || UnixSocketPermissionParsed > 0777 {
2019-04-02 08:48:31 +01:00
log.Fatal("Failed to parse unixSocketPermission: %s", UnixSocketPermissionRaw)
2016-08-11 14:55:10 -07:00
}
UnixSocketPermission = uint32(UnixSocketPermissionParsed)
2014-11-03 20:46:53 -05:00
}
EnableLetsEncrypt = sec.Key("ENABLE_LETSENCRYPT").MustBool(false)
LetsEncryptTOS = sec.Key("LETSENCRYPT_ACCEPTTOS").MustBool(false)
2018-08-21 09:56:50 -04:00
if !LetsEncryptTOS && EnableLetsEncrypt {
log.Warn("Failed to enable Let's Encrypt due to Let's Encrypt TOS not being accepted")
EnableLetsEncrypt = false
}
LetsEncryptDirectory = sec.Key("LETSENCRYPT_DIRECTORY").MustString("https")
LetsEncryptEmail = sec.Key("LETSENCRYPT_EMAIL").MustString("")
2014-12-31 18:37:29 +08:00
Domain = sec.Key("DOMAIN").MustString("localhost")
2016-08-11 14:55:10 -07:00
HTTPAddr = sec.Key("HTTP_ADDR").MustString("0.0.0.0")
HTTPPort = sec.Key("HTTP_PORT").MustString("3000")
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)
defaultAppURL := string(Protocol) + "://" + Domain
if (Protocol == HTTP && HTTPPort != "80") || (Protocol == HTTPS && HTTPPort != "443") {
defaultAppURL += ":" + HTTPPort
}
AppURL = sec.Key("ROOT_URL").MustString(defaultAppURL)
AppURL = strings.TrimSuffix(AppURL, "/") + "/"
// Check if has app suburl.
2019-06-12 16:07:24 -05:00
appURL, err := url.Parse(AppURL)
if err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("Invalid ROOT_URL '%s': %s", AppURL, err)
}
// Suburl should start with '/' and end without '/', such as '/{subpath}'.
// This value is empty if site does not have sub-url.
2019-06-12 16:07:24 -05:00
AppSubURL = strings.TrimSuffix(appURL.Path, "/")
StaticURLPrefix = strings.TrimSuffix(sec.Key("STATIC_URL_PREFIX").MustString(AppSubURL), "/")
AppSubURLDepth = strings.Count(AppSubURL, "/")
// Check if Domain differs from AppURL domain than update it to AppURL's domain
2020-07-26 20:16:22 -04:00
urlHostname := appURL.Hostname()
if urlHostname != Domain && net.ParseIP(urlHostname) == nil && urlHostname != "" {
Domain = urlHostname
}
2020-12-23 20:09:54 +01:00
AbsoluteAssetURL = MakeAbsoluteAssetURL(AppURL, StaticURLPrefix)
manifestBytes := MakeManifestData(AppName, AppURL, AbsoluteAssetURL)
ManifestData = `application/json;base64,` + base64.StdEncoding.EncodeToString(manifestBytes)
var defaultLocalURL string
switch Protocol {
case UnixSocket:
defaultLocalURL = "http://unix/"
case FCGI:
defaultLocalURL = AppURL
2019-12-10 12:23:26 +00:00
case FCGIUnix:
defaultLocalURL = AppURL
default:
defaultLocalURL = string(Protocol) + "://"
if HTTPAddr == "0.0.0.0" {
2020-07-26 22:31:28 +02:00
defaultLocalURL += net.JoinHostPort("localhost", HTTPPort) + "/"
} else {
2020-07-26 22:31:28 +02:00
defaultLocalURL += net.JoinHostPort(HTTPAddr, HTTPPort) + "/"
}
}
LocalURL = sec.Key("LOCAL_ROOT_URL").MustString(defaultLocalURL)
RedirectOtherPort = sec.Key("REDIRECT_OTHER_PORT").MustBool(false)
PortToRedirect = sec.Key("PORT_TO_REDIRECT").MustString("80")
2014-12-31 18:37:29 +08:00
OfflineMode = sec.Key("OFFLINE_MODE").MustBool()
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"))
2014-12-31 18:37:29 +08:00
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)
}
2014-12-31 18:37:29 +08:00
switch sec.Key("LANDING_PAGE").MustString("home") {
2014-11-24 18:47:59 -05:00
case "explore":
2016-11-27 18:14:25 +08:00
LandingPageURL = LandingPageExplore
case "organizations":
LandingPageURL = LandingPageOrganizations
case "login":
LandingPageURL = LandingPageLogin
2014-11-24 18:47:59 -05:00
default:
2016-11-27 18:14:25 +08:00
LandingPageURL = LandingPageHome
2014-11-24 18:47:59 -05:00
}
if len(SSH.Domain) == 0 {
SSH.Domain = Domain
}
2016-02-27 20:48:39 -05:00
SSH.RootPath = path.Join(homeDir, ".ssh")
2017-10-23 23:20:44 +08:00
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
}
2016-02-27 20:48:39 -05:00
SSH.KeyTestPath = os.TempDir()
if err = Cfg.Section("server").MapTo(&SSH); err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("Failed to map SSH settings: %v", err)
2016-02-27 20:48:39 -05:00
}
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)
2016-02-27 20:48:39 -05:00
// When disable SSH, start builtin server value is ignored.
if SSH.Disabled {
SSH.StartBuiltinServer = false
}
2020-10-11 02:38:09 +02:00
trustedUserCaKeys := sec.Key("SSH_TRUSTED_USER_CA_KEYS").Strings(",")
for _, caKey := range 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(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(","))
2016-02-27 20:48:39 -05:00
if !SSH.Disabled && !SSH.StartBuiltinServer {
if err := os.MkdirAll(SSH.RootPath, 0700); err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("Failed to create '%s': %v", SSH.RootPath, err)
2016-02-27 20:48:39 -05:00
} else if err = os.MkdirAll(SSH.KeyTestPath, 0644); err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("Failed to create '%s': %v", SSH.KeyTestPath, err)
2016-02-27 20:48:39 -05:00
}
2020-10-11 02:38:09 +02:00
if len(trustedUserCaKeys) > 0 && SSH.AuthorizedPrincipalsEnabled {
fname := sec.Key("SSH_TRUSTED_USER_CA_KEYS_FILENAME").MustString(filepath.Join(SSH.RootPath, "gitea-trusted-user-ca-keys.pem"))
if err := ioutil.WriteFile(fname,
[]byte(strings.Join(trustedUserCaKeys, "\n")), 0600); err != nil {
log.Fatal("Failed to create '%s': %v", fname, err)
}
}
2016-02-27 20:48:39 -05:00
}
2020-10-09 07:52:57 +01:00
SSH.MinimumKeySizeCheck = sec.Key("MINIMUM_KEY_SIZE_CHECK").MustBool(SSH.MinimumKeySizeCheck)
2016-02-27 20:48:39 -05:00
minimumKeySizes := Cfg.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()))
2016-02-27 20:48:39 -05:00
}
}
2020-10-11 02:38:09 +02:00
SSH.AuthorizedKeysBackup = sec.Key("SSH_AUTHORIZED_KEYS_BACKUP").MustBool(true)
2018-11-01 13:41:07 +00:00
SSH.CreateAuthorizedKeysFile = sec.Key("SSH_CREATE_AUTHORIZED_KEYS_FILE").MustBool(true)
2020-10-11 02:38:09 +02:00
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)
2016-02-27 20:48:39 -05:00
2019-03-08 17:42:50 +01:00
if err = Cfg.Section("oauth2").MapTo(&OAuth2); err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("Failed to OAuth2 settings: %v", err)
2019-03-08 17:42:50 +01:00
return
}
if OAuth2.Enable {
OAuth2.JWTSecretBytes = make([]byte, 32)
n, err := base64.RawURLEncoding.Decode(OAuth2.JWTSecretBytes, []byte(OAuth2.JWTSecretBase64))
if err != nil || n != 32 {
OAuth2.JWTSecretBase64, err = generate.NewJwtSecret()
if err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("error generating JWT secret: %v", err)
2019-03-08 17:42:50 +01:00
return
}
cfg := ini.Empty()
isFile, err := util.IsFile(CustomConf)
if err != nil {
log.Error("Unable to check if %s is a file. Error: %v", CustomConf, err)
}
if isFile {
2019-03-08 17:42:50 +01:00
if err := cfg.Append(CustomConf); err != nil {
2019-04-02 08:48:31 +01:00
log.Error("failed to load custom conf %s: %v", CustomConf, err)
2019-03-08 17:42:50 +01:00
return
}
}
cfg.Section("oauth2").Key("JWT_SECRET").SetValue(OAuth2.JWTSecretBase64)
if err := os.MkdirAll(filepath.Dir(CustomConf), os.ModePerm); err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("failed to create '%s': %v", CustomConf, err)
2019-03-08 17:42:50 +01:00
return
}
if err := cfg.SaveTo(CustomConf); err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("error saving generating JWT secret to custom config: %v", err)
2019-03-08 17:42:50 +01:00
return
}
}
}
sec = Cfg.Section("admin")
Admin.DefaultEmailNotification = sec.Key("DEFAULT_EMAIL_NOTIFICATIONS").MustString("enabled")
2014-12-31 18:37:29 +08:00
sec = Cfg.Section("security")
2016-12-23 15:18:05 +08:00
InstallLock = sec.Key("INSTALL_LOCK").MustBool(false)
SecretKey = sec.Key("SECRET_KEY").MustString("!#@FDEWREWR&*(")
LogInRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt(7)
CookieUserName = sec.Key("COOKIE_USERNAME").MustString("gitea_awesome")
CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").MustString("gitea_incredible")
2014-12-31 18:37:29 +08:00
ReverseProxyAuthUser = sec.Key("REVERSE_PROXY_AUTHENTICATION_USER").MustString("X-WEBAUTH-USER")
ReverseProxyAuthEmail = sec.Key("REVERSE_PROXY_AUTHENTICATION_EMAIL").MustString("X-WEBAUTH-EMAIL")
2016-12-24 15:42:11 +01:00
MinPasswordLength = sec.Key("MIN_PASSWORD_LENGTH").MustInt(6)
ImportLocalPaths = sec.Key("IMPORT_LOCAL_PATHS").MustBool(false)
2020-10-07 14:24:14 -04:00
DisableGitHooks = sec.Key("DISABLE_GIT_HOOKS").MustBool(true)
2021-02-11 18:34:34 +01:00
DisableWebhooks = sec.Key("DISABLE_WEBHOOKS").MustBool(false)
OnlyAllowPushIfGiteaEnvironmentSet = sec.Key("ONLY_ALLOW_PUSH_IF_GITEA_ENVIRONMENT_SET").MustBool(true)
PasswordHashAlgo = sec.Key("PASSWORD_HASH_ALGO").MustString("pbkdf2")
2019-07-12 06:57:31 -07:00
CSRFCookieHTTPOnly = sec.Key("CSRF_COOKIE_HTTP_ONLY").MustBool(true)
PasswordCheckPwn = sec.Key("PASSWORD_CHECK_PWN").MustBool(false)
2019-07-12 06:57:31 -07:00
InternalToken = loadInternalToken(sec)
2014-12-31 18:37:29 +08:00
2019-10-14 22:24:26 +07:00
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)
2019-10-14 22:24:26 +07:00
}
}
newAttachmentService()
2020-09-29 17:05:13 +08:00
newLFSService()
2014-07-23 21:15:47 +02:00
timeFormatKey := Cfg.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 := Cfg.Section("time").Key("DEFAULT_UI_LOCATION").String()
if zone != "" {
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)
2017-02-04 14:37:50 +02:00
}
}
if DefaultUILocation == nil {
DefaultUILocation = time.Local
2017-02-04 14:37:50 +02:00
}
RunUser = Cfg.Section("").Key("RUN_USER").MustString(user.CurrentUsername())
2020-11-30 20:52:04 +01:00
RunMode = Cfg.Section("").Key("RUN_MODE").MustString("prod")
2014-05-25 20:11:25 -04:00
// Does not check run user when the install lock is off.
2016-08-09 17:41:18 -07:00
if InstallLock {
currentUser, match := IsRunUserMatchCurrentUser(RunUser)
if !match {
2019-04-02 08:48:31 +01:00
log.Fatal("Expect user '%s' but current user is: %s", RunUser, currentUser)
2016-08-09 17:41:18 -07:00
}
2014-05-25 20:11:25 -04:00
}
SSH.BuiltinServerUser = Cfg.Section("server").Key("BUILTIN_SSH_SERVER_USER").MustString(RunUser)
2019-03-16 11:12:44 +08:00
newRepository()
2016-08-11 05:48:08 -07:00
newPictureService()
2014-07-26 00:24:27 -04:00
2016-07-24 00:23:54 +08:00
if err = Cfg.Section("ui").MapTo(&UI); err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("Failed to map UI settings: %v", err)
2016-07-24 00:23:54 +08:00
} else if err = Cfg.Section("markdown").MapTo(&Markdown); err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("Failed to map Markdown settings: %v", err)
} else if err = Cfg.Section("admin").MapTo(&Admin); err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("Fail to map Admin settings: %v", err)
2016-08-09 23:58:15 -07:00
} else if err = Cfg.Section("api").MapTo(&API); err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("Failed to map API settings: %v", err)
2018-11-05 06:20:00 +03:00
} else if err = Cfg.Section("metrics").MapTo(&Metrics); err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("Failed to map Metrics settings: %v", err)
}
2019-06-12 16:07:24 -05:00
u := *appURL
u.Path = path.Join(u.Path, "api", "swagger")
API.SwaggerURL = u.String()
2019-03-16 11:12:44 +08:00
newGit()
sec = Cfg.Section("mirror")
Mirror.MinInterval = sec.Key("MIN_INTERVAL").MustDuration(10 * time.Minute)
Mirror.DefaultInterval = sec.Key("DEFAULT_INTERVAL").MustDuration(8 * time.Hour)
if Mirror.MinInterval.Minutes() < 1 {
log.Warn("Mirror.MinInterval is too low")
Mirror.MinInterval = 1 * time.Minute
}
if Mirror.DefaultInterval < Mirror.MinInterval {
log.Warn("Mirror.DefaultInterval is less than Mirror.MinInterval")
Mirror.DefaultInterval = time.Hour * 8
2015-01-02 20:14:43 +08:00
}
2014-09-17 12:03:03 +08:00
2014-12-31 18:37:29 +08:00
Langs = Cfg.Section("i18n").Key("LANGS").Strings(",")
if len(Langs) == 0 {
Langs = []string{
"en-US", "zh-CN", "zh-HK", "zh-TW", "de-DE", "fr-FR", "nl-NL", "lv-LV",
2020-06-05 09:07:56 +01:00
"ru-RU", "uk-UA", "ja-JP", "es-ES", "pt-BR", "pt-PT", "pl-PL", "bg-BG",
"it-IT", "fi-FI", "tr-TR", "cs-CZ", "sr-SP", "sv-SE", "ko-KR"}
}
2014-12-31 18:37:29 +08:00
Names = Cfg.Section("i18n").Key("NAMES").Strings(",")
if len(Names) == 0 {
Names = []string{"English", "简体中文", "繁體中文(香港)", "繁體中文(台灣)", "Deutsch",
"français", "Nederlands", "latviešu", "русский", "Українська", "日本語",
2020-06-05 09:07:56 +01:00
"español", "português do Brasil", "Português de Portugal", "polski", "български",
"italiano", "suomi", "Türkçe", "čeština", "српски", "svenska", "한국어"}
}
2014-09-21 19:39:10 -04:00
2016-12-23 15:18:05 +08:00
ShowFooterBranding = Cfg.Section("other").Key("SHOW_FOOTER_BRANDING").MustBool(false)
ShowFooterVersion = Cfg.Section("other").Key("SHOW_FOOTER_VERSION").MustBool(true)
ShowFooterTemplateLoadTime = Cfg.Section("other").Key("SHOW_FOOTER_TEMPLATE_LOAD_TIME").MustBool(true)
UI.ShowUserEmail = Cfg.Section("ui").Key("SHOW_USER_EMAIL").MustBool(true)
UI.DefaultShowFullName = Cfg.Section("ui").Key("DEFAULT_SHOW_FULL_NAME").MustBool(false)
UI.SearchRepoDescription = Cfg.Section("ui").Key("SEARCH_REPO_DESCRIPTION").MustBool(true)
2019-11-21 21:06:23 +01:00
UI.UseServiceWorker = Cfg.Section("ui").Key("USE_SERVICE_WORKER").MustBool(true)
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)
}
2017-11-07 14:33:06 +08:00
2019-03-16 11:12:44 +08:00
newMarkup()
2019-02-19 22:39:39 +08:00
2018-05-19 16:12:37 +02:00
sec = Cfg.Section("U2F")
U2F.TrustedFacets, _ = shellquote.Split(sec.Key("TRUSTED_FACETS").MustString(strings.TrimSuffix(AppURL, AppSubURL+"/")))
U2F.AppID = sec.Key("APP_ID").MustString(strings.TrimSuffix(AppURL, "/"))
2019-12-07 23:04:19 +01:00
UI.ReactionsMap = make(map[string]bool)
for _, reaction := range UI.Reactions {
UI.ReactionsMap[reaction] = true
}
2014-05-25 20:11:25 -04:00
}
2020-10-11 02:38:09 +02:00
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 loadInternalToken(sec *ini.Section) string {
uri := sec.Key("INTERNAL_TOKEN_URI").String()
if len(uri) == 0 {
return loadOrGenerateInternalToken(sec)
}
tempURI, err := url.Parse(uri)
if err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("Failed to parse INTERNAL_TOKEN_URI (%s): %v", uri, err)
}
switch tempURI.Scheme {
case "file":
fp, err := os.OpenFile(tempURI.RequestURI(), os.O_RDWR, 0600)
if err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("Failed to open InternalTokenURI (%s): %v", uri, err)
}
defer fp.Close()
buf, err := ioutil.ReadAll(fp)
if err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("Failed to read InternalTokenURI (%s): %v", uri, err)
}
// No token in the file, generate one and store it.
if len(buf) == 0 {
token, err := generate.NewInternalToken()
if err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("Error generate internal token: %v", err)
}
if _, err := io.WriteString(fp, token); err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("Error writing to InternalTokenURI (%s): %v", uri, err)
}
return token
}
return strings.TrimSpace(string(buf))
default:
2019-04-02 08:48:31 +01:00
log.Fatal("Unsupported URI-Scheme %q (INTERNAL_TOKEN_URI = %q)", tempURI.Scheme, uri)
}
return ""
}
func loadOrGenerateInternalToken(sec *ini.Section) string {
var err error
token := sec.Key("INTERNAL_TOKEN").String()
if len(token) == 0 {
token, err = generate.NewInternalToken()
if err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("Error generate internal token: %v", err)
}
// Save secret
cfgSave := ini.Empty()
isFile, err := util.IsFile(CustomConf)
if err != nil {
log.Error("Unable to check if %s is a file. Error: %v", CustomConf, err)
}
if isFile {
// Keeps custom settings if there is already something.
if err := cfgSave.Append(CustomConf); err != nil {
2019-04-02 08:48:31 +01:00
log.Error("Failed to load custom conf '%s': %v", CustomConf, err)
}
}
cfgSave.Section("security").Key("INTERNAL_TOKEN").SetValue(token)
if err := os.MkdirAll(filepath.Dir(CustomConf), os.ModePerm); err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("Failed to create '%s': %v", CustomConf, err)
}
if err := cfgSave.SaveTo(CustomConf); err != nil {
2019-04-02 08:48:31 +01:00
log.Fatal("Error saving generated INTERNAL_TOKEN to custom config: %v", err)
}
}
return token
}
2020-12-23 20:09:54 +01:00
// MakeAbsoluteAssetURL returns the absolute asset url prefix without a trailing slash
func MakeAbsoluteAssetURL(appURL string, 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 strings.TrimSuffix(appURL, "/") + strings.TrimSuffix(staticURLPrefix, "/")
}
return strings.TrimSuffix(staticURLPrefix, "/")
}
// MakeManifestData generates web app manifest JSON
func MakeManifestData(appName string, appURL string, 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 + "/img/logo.png",
2020-12-23 20:09:54 +01:00
Type: "image/png",
Sizes: "512x512",
},
{
Src: absoluteAssetURL + "/img/logo.svg",
Type: "image/svg+xml",
Sizes: "512x512",
2020-12-23 20:09:54 +01:00
},
},
})
if err != nil {
log.Error("unable to marshal manifest JSON. Error: %v", err)
return make([]byte, 0)
}
2020-12-22 12:13:50 +01:00
2020-12-23 20:09:54 +01:00
return bytes
2020-12-22 12:13:50 +01:00
}
2016-11-27 18:14:25 +08:00
// NewServices initializes the services
2014-05-25 20:11:25 -04:00
func NewServices() {
InitDBConfig()
2014-04-10 14:20:58 -04:00
newService()
2019-04-07 01:25:14 +01:00
NewLogServices(false)
2014-04-10 14:20:58 -04:00
newCacheService()
newSessionService()
2019-05-13 08:38:53 -07:00
newCORSService()
2014-04-10 14:20:58 -04:00
newMailService()
newRegisterMailService()
newNotifyMailService()
2014-06-08 04:45:34 -04:00
newWebhookService()
newMigrationsService()
2019-02-19 22:39:39 +08:00
newIndexerService()
newTaskService()
NewQueueService()
2020-08-17 04:07:38 +01:00
newProject()
2014-04-10 14:20:58 -04:00
}