You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

setting.go 37KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Copyright 2017 The Gitea Authors. All rights reserved.
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. package setting
  6. import (
  7. "encoding/base64"
  8. "fmt"
  9. "io"
  10. "io/ioutil"
  11. "math"
  12. "net"
  13. "net/url"
  14. "os"
  15. "os/exec"
  16. "path"
  17. "path/filepath"
  18. "runtime"
  19. "strconv"
  20. "strings"
  21. "time"
  22. "code.gitea.io/gitea/modules/generate"
  23. "code.gitea.io/gitea/modules/git"
  24. "code.gitea.io/gitea/modules/log"
  25. "code.gitea.io/gitea/modules/user"
  26. shellquote "github.com/kballard/go-shellquote"
  27. version "github.com/mcuadros/go-version"
  28. "github.com/unknwon/cae/zip"
  29. "github.com/unknwon/com"
  30. ini "gopkg.in/ini.v1"
  31. "strk.kbt.io/projects/go/libravatar"
  32. )
  33. // Scheme describes protocol types
  34. type Scheme string
  35. // enumerates all the scheme types
  36. const (
  37. HTTP Scheme = "http"
  38. HTTPS Scheme = "https"
  39. FCGI Scheme = "fcgi"
  40. FCGIUnix Scheme = "fcgi+unix"
  41. UnixSocket Scheme = "unix"
  42. )
  43. // LandingPage describes the default page
  44. type LandingPage string
  45. // enumerates all the landing page types
  46. const (
  47. LandingPageHome LandingPage = "/"
  48. LandingPageExplore LandingPage = "/explore"
  49. LandingPageOrganizations LandingPage = "/explore/organizations"
  50. LandingPageLogin LandingPage = "/user/login"
  51. )
  52. // enumerates all the types of captchas
  53. const (
  54. ImageCaptcha = "image"
  55. ReCaptcha = "recaptcha"
  56. )
  57. // settings
  58. var (
  59. // AppVer settings
  60. AppVer string
  61. AppBuiltWith string
  62. AppName string
  63. AppURL string
  64. AppSubURL string
  65. AppSubURLDepth int // Number of slashes
  66. AppPath string
  67. AppDataPath string
  68. AppWorkPath string
  69. // Server settings
  70. Protocol Scheme
  71. Domain string
  72. HTTPAddr string
  73. HTTPPort string
  74. LocalURL string
  75. RedirectOtherPort bool
  76. PortToRedirect string
  77. OfflineMode bool
  78. CertFile string
  79. KeyFile string
  80. StaticRootPath string
  81. StaticCacheTime time.Duration
  82. EnableGzip bool
  83. LandingPageURL LandingPage
  84. UnixSocketPermission uint32
  85. EnablePprof bool
  86. PprofDataPath string
  87. EnableLetsEncrypt bool
  88. LetsEncryptTOS bool
  89. LetsEncryptDirectory string
  90. LetsEncryptEmail string
  91. GracefulRestartable bool
  92. GracefulHammerTime time.Duration
  93. StartupTimeout time.Duration
  94. StaticURLPrefix string
  95. SSH = struct {
  96. Disabled bool `ini:"DISABLE_SSH"`
  97. StartBuiltinServer bool `ini:"START_SSH_SERVER"`
  98. BuiltinServerUser string `ini:"BUILTIN_SSH_SERVER_USER"`
  99. Domain string `ini:"SSH_DOMAIN"`
  100. Port int `ini:"SSH_PORT"`
  101. ListenHost string `ini:"SSH_LISTEN_HOST"`
  102. ListenPort int `ini:"SSH_LISTEN_PORT"`
  103. RootPath string `ini:"SSH_ROOT_PATH"`
  104. ServerCiphers []string `ini:"SSH_SERVER_CIPHERS"`
  105. ServerKeyExchanges []string `ini:"SSH_SERVER_KEY_EXCHANGES"`
  106. ServerMACs []string `ini:"SSH_SERVER_MACS"`
  107. KeyTestPath string `ini:"SSH_KEY_TEST_PATH"`
  108. KeygenPath string `ini:"SSH_KEYGEN_PATH"`
  109. AuthorizedKeysBackup bool `ini:"SSH_AUTHORIZED_KEYS_BACKUP"`
  110. MinimumKeySizeCheck bool `ini:"-"`
  111. MinimumKeySizes map[string]int `ini:"-"`
  112. CreateAuthorizedKeysFile bool `ini:"SSH_CREATE_AUTHORIZED_KEYS_FILE"`
  113. ExposeAnonymous bool `ini:"SSH_EXPOSE_ANONYMOUS"`
  114. }{
  115. Disabled: false,
  116. StartBuiltinServer: false,
  117. Domain: "",
  118. Port: 22,
  119. ServerCiphers: []string{"aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", "arcfour256", "arcfour128"},
  120. ServerKeyExchanges: []string{"diffie-hellman-group1-sha1", "diffie-hellman-group14-sha1", "ecdh-sha2-nistp256", "ecdh-sha2-nistp384", "ecdh-sha2-nistp521", "curve25519-sha256@libssh.org"},
  121. ServerMACs: []string{"hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha1", "hmac-sha1-96"},
  122. KeygenPath: "ssh-keygen",
  123. MinimumKeySizes: map[string]int{"ed25519": 256, "ecdsa": 256, "rsa": 2048, "dsa": 1024},
  124. }
  125. LFS struct {
  126. StartServer bool `ini:"LFS_START_SERVER"`
  127. ContentPath string `ini:"LFS_CONTENT_PATH"`
  128. JWTSecretBase64 string `ini:"LFS_JWT_SECRET"`
  129. JWTSecretBytes []byte `ini:"-"`
  130. HTTPAuthExpiry time.Duration `ini:"LFS_HTTP_AUTH_EXPIRY"`
  131. MaxFileSize int64 `ini:"LFS_MAX_FILE_SIZE"`
  132. LocksPagingNum int `ini:"LFS_LOCKS_PAGING_NUM"`
  133. }
  134. // Security settings
  135. InstallLock bool
  136. SecretKey string
  137. LogInRememberDays int
  138. CookieUserName string
  139. CookieRememberName string
  140. ReverseProxyAuthUser string
  141. ReverseProxyAuthEmail string
  142. MinPasswordLength int
  143. ImportLocalPaths bool
  144. DisableGitHooks bool
  145. OnlyAllowPushIfGiteaEnvironmentSet bool
  146. PasswordComplexity []string
  147. PasswordHashAlgo string
  148. // UI settings
  149. UI = struct {
  150. ExplorePagingNum int
  151. IssuePagingNum int
  152. RepoSearchPagingNum int
  153. MembersPagingNum int
  154. FeedMaxCommitNum int
  155. GraphMaxCommitNum int
  156. CodeCommentLines int
  157. ReactionMaxUserNum int
  158. ThemeColorMetaTag string
  159. MaxDisplayFileSize int64
  160. ShowUserEmail bool
  161. DefaultShowFullName bool
  162. DefaultTheme string
  163. Themes []string
  164. Reactions []string
  165. ReactionsMap map[string]bool
  166. SearchRepoDescription bool
  167. UseServiceWorker bool
  168. Notification struct {
  169. MinTimeout time.Duration
  170. TimeoutStep time.Duration
  171. MaxTimeout time.Duration
  172. EventSourceUpdateTime time.Duration
  173. } `ini:"ui.notification"`
  174. Admin struct {
  175. UserPagingNum int
  176. RepoPagingNum int
  177. NoticePagingNum int
  178. OrgPagingNum int
  179. } `ini:"ui.admin"`
  180. User struct {
  181. RepoPagingNum int
  182. } `ini:"ui.user"`
  183. Meta struct {
  184. Author string
  185. Description string
  186. Keywords string
  187. } `ini:"ui.meta"`
  188. }{
  189. ExplorePagingNum: 20,
  190. IssuePagingNum: 10,
  191. RepoSearchPagingNum: 10,
  192. MembersPagingNum: 20,
  193. FeedMaxCommitNum: 5,
  194. GraphMaxCommitNum: 100,
  195. CodeCommentLines: 4,
  196. ReactionMaxUserNum: 10,
  197. ThemeColorMetaTag: `#6cc644`,
  198. MaxDisplayFileSize: 8388608,
  199. DefaultTheme: `gitea`,
  200. Themes: []string{`gitea`, `arc-green`},
  201. Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`},
  202. Notification: struct {
  203. MinTimeout time.Duration
  204. TimeoutStep time.Duration
  205. MaxTimeout time.Duration
  206. EventSourceUpdateTime time.Duration
  207. }{
  208. MinTimeout: 10 * time.Second,
  209. TimeoutStep: 10 * time.Second,
  210. MaxTimeout: 60 * time.Second,
  211. EventSourceUpdateTime: 10 * time.Second,
  212. },
  213. Admin: struct {
  214. UserPagingNum int
  215. RepoPagingNum int
  216. NoticePagingNum int
  217. OrgPagingNum int
  218. }{
  219. UserPagingNum: 50,
  220. RepoPagingNum: 50,
  221. NoticePagingNum: 25,
  222. OrgPagingNum: 50,
  223. },
  224. User: struct {
  225. RepoPagingNum int
  226. }{
  227. RepoPagingNum: 15,
  228. },
  229. Meta: struct {
  230. Author string
  231. Description string
  232. Keywords string
  233. }{
  234. Author: "Gitea - Git with a cup of tea",
  235. Description: "Gitea (Git with a cup of tea) is a painless self-hosted Git service written in Go",
  236. Keywords: "go,git,self-hosted,gitea",
  237. },
  238. }
  239. // Markdown settings
  240. Markdown = struct {
  241. EnableHardLineBreak bool
  242. CustomURLSchemes []string `ini:"CUSTOM_URL_SCHEMES"`
  243. FileExtensions []string
  244. }{
  245. EnableHardLineBreak: true,
  246. FileExtensions: strings.Split(".md,.markdown,.mdown,.mkd", ","),
  247. }
  248. // Admin settings
  249. Admin struct {
  250. DisableRegularOrgCreation bool
  251. DefaultEmailNotification string
  252. }
  253. // Picture settings
  254. AvatarUploadPath string
  255. AvatarMaxWidth int
  256. AvatarMaxHeight int
  257. GravatarSource string
  258. GravatarSourceURL *url.URL
  259. DisableGravatar bool
  260. EnableFederatedAvatar bool
  261. LibravatarService *libravatar.Libravatar
  262. AvatarMaxFileSize int64
  263. RepositoryAvatarUploadPath string
  264. RepositoryAvatarFallback string
  265. RepositoryAvatarFallbackImage string
  266. // Log settings
  267. LogLevel string
  268. StacktraceLogLevel string
  269. LogRootPath string
  270. LogDescriptions = make(map[string]*LogDescription)
  271. RedirectMacaronLog bool
  272. DisableRouterLog bool
  273. RouterLogLevel log.Level
  274. RouterLogMode string
  275. EnableAccessLog bool
  276. AccessLogTemplate string
  277. EnableXORMLog bool
  278. // Attachment settings
  279. AttachmentPath string
  280. AttachmentAllowedTypes string
  281. AttachmentMaxSize int64
  282. AttachmentMaxFiles int
  283. AttachmentEnabled bool
  284. // Time settings
  285. TimeFormat string
  286. // UILocation is the location on the UI, so that we can display the time on UI.
  287. DefaultUILocation = time.Local
  288. CSRFCookieName = "_csrf"
  289. CSRFCookieHTTPOnly = true
  290. // Mirror settings
  291. Mirror struct {
  292. DefaultInterval time.Duration
  293. MinInterval time.Duration
  294. }
  295. // API settings
  296. API = struct {
  297. EnableSwagger bool
  298. SwaggerURL string
  299. MaxResponseItems int
  300. DefaultPagingNum int
  301. DefaultGitTreesPerPage int
  302. DefaultMaxBlobSize int64
  303. }{
  304. EnableSwagger: true,
  305. SwaggerURL: "",
  306. MaxResponseItems: 50,
  307. DefaultPagingNum: 30,
  308. DefaultGitTreesPerPage: 1000,
  309. DefaultMaxBlobSize: 10485760,
  310. }
  311. OAuth2 = struct {
  312. Enable bool
  313. AccessTokenExpirationTime int64
  314. RefreshTokenExpirationTime int64
  315. InvalidateRefreshTokens bool
  316. JWTSecretBytes []byte `ini:"-"`
  317. JWTSecretBase64 string `ini:"JWT_SECRET"`
  318. MaxTokenLength int
  319. }{
  320. Enable: true,
  321. AccessTokenExpirationTime: 3600,
  322. RefreshTokenExpirationTime: 730,
  323. InvalidateRefreshTokens: false,
  324. MaxTokenLength: math.MaxInt16,
  325. }
  326. U2F = struct {
  327. AppID string
  328. TrustedFacets []string
  329. }{}
  330. // Metrics settings
  331. Metrics = struct {
  332. Enabled bool
  333. Token string
  334. }{
  335. Enabled: false,
  336. Token: "",
  337. }
  338. // I18n settings
  339. Langs []string
  340. Names []string
  341. dateLangs map[string]string
  342. // Highlight settings are loaded in modules/template/highlight.go
  343. // Other settings
  344. ShowFooterBranding bool
  345. ShowFooterVersion bool
  346. ShowFooterTemplateLoadTime bool
  347. // Global setting objects
  348. Cfg *ini.File
  349. CustomPath string // Custom directory path
  350. CustomConf string
  351. CustomPID string
  352. ProdMode bool
  353. RunUser string
  354. IsWindows bool
  355. HasRobotsTxt bool
  356. InternalToken string // internal access token
  357. // UILocation is the location on the UI, so that we can display the time on UI.
  358. // Currently only show the default time.Local, it could be added to app.ini after UI is ready
  359. UILocation = time.Local
  360. )
  361. // DateLang transforms standard language locale name to corresponding value in datetime plugin.
  362. func DateLang(lang string) string {
  363. name, ok := dateLangs[lang]
  364. if ok {
  365. return name
  366. }
  367. return "en"
  368. }
  369. func getAppPath() (string, error) {
  370. var appPath string
  371. var err error
  372. if IsWindows && filepath.IsAbs(os.Args[0]) {
  373. appPath = filepath.Clean(os.Args[0])
  374. } else {
  375. appPath, err = exec.LookPath(os.Args[0])
  376. }
  377. if err != nil {
  378. return "", err
  379. }
  380. appPath, err = filepath.Abs(appPath)
  381. if err != nil {
  382. return "", err
  383. }
  384. // Note: we don't use path.Dir here because it does not handle case
  385. // which path starts with two "/" in Windows: "//psf/Home/..."
  386. return strings.Replace(appPath, "\\", "/", -1), err
  387. }
  388. func getWorkPath(appPath string) string {
  389. workPath := AppWorkPath
  390. if giteaWorkPath, ok := os.LookupEnv("GITEA_WORK_DIR"); ok {
  391. workPath = giteaWorkPath
  392. }
  393. if len(workPath) == 0 {
  394. i := strings.LastIndex(appPath, "/")
  395. if i == -1 {
  396. workPath = appPath
  397. } else {
  398. workPath = appPath[:i]
  399. }
  400. }
  401. return strings.Replace(workPath, "\\", "/", -1)
  402. }
  403. func init() {
  404. IsWindows = runtime.GOOS == "windows"
  405. // We can rely on log.CanColorStdout being set properly because modules/log/console_windows.go comes before modules/setting/setting.go lexicographically
  406. log.NewLogger(0, "console", "console", fmt.Sprintf(`{"level": "trace", "colorize": %t, "stacktraceLevel": "none"}`, log.CanColorStdout))
  407. var err error
  408. if AppPath, err = getAppPath(); err != nil {
  409. log.Fatal("Failed to get app path: %v", err)
  410. }
  411. AppWorkPath = getWorkPath(AppPath)
  412. }
  413. func forcePathSeparator(path string) {
  414. if strings.Contains(path, "\\") {
  415. log.Fatal("Do not use '\\' or '\\\\' in paths, instead, please use '/' in all places")
  416. }
  417. }
  418. // IsRunUserMatchCurrentUser returns false if configured run user does not match
  419. // actual user that runs the app. The first return value is the actual user name.
  420. // This check is ignored under Windows since SSH remote login is not the main
  421. // method to login on Windows.
  422. func IsRunUserMatchCurrentUser(runUser string) (string, bool) {
  423. if IsWindows || SSH.StartBuiltinServer {
  424. return "", true
  425. }
  426. currentUser := user.CurrentUsername()
  427. return currentUser, runUser == currentUser
  428. }
  429. func createPIDFile(pidPath string) {
  430. currentPid := os.Getpid()
  431. if err := os.MkdirAll(filepath.Dir(pidPath), os.ModePerm); err != nil {
  432. log.Fatal("Failed to create PID folder: %v", err)
  433. }
  434. file, err := os.Create(pidPath)
  435. if err != nil {
  436. log.Fatal("Failed to create PID file: %v", err)
  437. }
  438. defer file.Close()
  439. if _, err := file.WriteString(strconv.FormatInt(int64(currentPid), 10)); err != nil {
  440. log.Fatal("Failed to write PID information: %v", err)
  441. }
  442. }
  443. // CheckLFSVersion will check lfs version, if not satisfied, then disable it.
  444. func CheckLFSVersion() {
  445. if LFS.StartServer {
  446. //Disable LFS client hooks if installed for the current OS user
  447. //Needs at least git v2.1.2
  448. binVersion, err := git.BinVersion()
  449. if err != nil {
  450. log.Fatal("Error retrieving git version: %v", err)
  451. }
  452. if !version.Compare(binVersion, "2.1.2", ">=") {
  453. LFS.StartServer = false
  454. log.Error("LFS server support needs at least Git v2.1.2")
  455. } else {
  456. git.GlobalCommandArgs = append(git.GlobalCommandArgs, "-c", "filter.lfs.required=",
  457. "-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=")
  458. }
  459. }
  460. }
  461. // SetCustomPathAndConf will set CustomPath and CustomConf with reference to the
  462. // GITEA_CUSTOM environment variable and with provided overrides before stepping
  463. // back to the default
  464. func SetCustomPathAndConf(providedCustom, providedConf, providedWorkPath string) {
  465. if len(providedWorkPath) != 0 {
  466. AppWorkPath = filepath.ToSlash(providedWorkPath)
  467. }
  468. if giteaCustom, ok := os.LookupEnv("GITEA_CUSTOM"); ok {
  469. CustomPath = giteaCustom
  470. }
  471. if len(providedCustom) != 0 {
  472. CustomPath = providedCustom
  473. }
  474. if len(CustomPath) == 0 {
  475. CustomPath = path.Join(AppWorkPath, "custom")
  476. } else if !filepath.IsAbs(CustomPath) {
  477. CustomPath = path.Join(AppWorkPath, CustomPath)
  478. }
  479. if len(providedConf) != 0 {
  480. CustomConf = providedConf
  481. }
  482. if len(CustomConf) == 0 {
  483. CustomConf = path.Join(CustomPath, "conf/app.ini")
  484. } else if !filepath.IsAbs(CustomConf) {
  485. CustomConf = path.Join(CustomPath, CustomConf)
  486. log.Warn("Using 'custom' directory as relative origin for configuration file: '%s'", CustomConf)
  487. }
  488. }
  489. // NewContext initializes configuration context.
  490. // NOTE: do not print any log except error.
  491. func NewContext() {
  492. Cfg = ini.Empty()
  493. if len(CustomPID) > 0 {
  494. createPIDFile(CustomPID)
  495. }
  496. if com.IsFile(CustomConf) {
  497. if err := Cfg.Append(CustomConf); err != nil {
  498. log.Fatal("Failed to load custom conf '%s': %v", CustomConf, err)
  499. }
  500. } else {
  501. log.Warn("Custom config '%s' not found, ignore this if you're running first time", CustomConf)
  502. }
  503. Cfg.NameMapper = ini.SnackCase
  504. homeDir, err := com.HomeDir()
  505. if err != nil {
  506. log.Fatal("Failed to get home directory: %v", err)
  507. }
  508. homeDir = strings.Replace(homeDir, "\\", "/", -1)
  509. LogLevel = getLogLevel(Cfg.Section("log"), "LEVEL", "Info")
  510. StacktraceLogLevel = getStacktraceLogLevel(Cfg.Section("log"), "STACKTRACE_LEVEL", "None")
  511. LogRootPath = Cfg.Section("log").Key("ROOT_PATH").MustString(path.Join(AppWorkPath, "log"))
  512. forcePathSeparator(LogRootPath)
  513. RedirectMacaronLog = Cfg.Section("log").Key("REDIRECT_MACARON_LOG").MustBool(false)
  514. RouterLogLevel = log.FromString(Cfg.Section("log").Key("ROUTER_LOG_LEVEL").MustString("Info"))
  515. sec := Cfg.Section("server")
  516. AppName = Cfg.Section("").Key("APP_NAME").MustString("Gitea: Git with a cup of tea")
  517. Protocol = HTTP
  518. switch sec.Key("PROTOCOL").String() {
  519. case "https":
  520. Protocol = HTTPS
  521. CertFile = sec.Key("CERT_FILE").String()
  522. KeyFile = sec.Key("KEY_FILE").String()
  523. if !filepath.IsAbs(CertFile) && len(CertFile) > 0 {
  524. CertFile = filepath.Join(CustomPath, CertFile)
  525. }
  526. if !filepath.IsAbs(KeyFile) && len(KeyFile) > 0 {
  527. KeyFile = filepath.Join(CustomPath, KeyFile)
  528. }
  529. case "fcgi":
  530. Protocol = FCGI
  531. case "fcgi+unix":
  532. Protocol = FCGIUnix
  533. UnixSocketPermissionRaw := sec.Key("UNIX_SOCKET_PERMISSION").MustString("666")
  534. UnixSocketPermissionParsed, err := strconv.ParseUint(UnixSocketPermissionRaw, 8, 32)
  535. if err != nil || UnixSocketPermissionParsed > 0777 {
  536. log.Fatal("Failed to parse unixSocketPermission: %s", UnixSocketPermissionRaw)
  537. }
  538. UnixSocketPermission = uint32(UnixSocketPermissionParsed)
  539. case "unix":
  540. Protocol = UnixSocket
  541. UnixSocketPermissionRaw := sec.Key("UNIX_SOCKET_PERMISSION").MustString("666")
  542. UnixSocketPermissionParsed, err := strconv.ParseUint(UnixSocketPermissionRaw, 8, 32)
  543. if err != nil || UnixSocketPermissionParsed > 0777 {
  544. log.Fatal("Failed to parse unixSocketPermission: %s", UnixSocketPermissionRaw)
  545. }
  546. UnixSocketPermission = uint32(UnixSocketPermissionParsed)
  547. }
  548. EnableLetsEncrypt = sec.Key("ENABLE_LETSENCRYPT").MustBool(false)
  549. LetsEncryptTOS = sec.Key("LETSENCRYPT_ACCEPTTOS").MustBool(false)
  550. if !LetsEncryptTOS && EnableLetsEncrypt {
  551. log.Warn("Failed to enable Let's Encrypt due to Let's Encrypt TOS not being accepted")
  552. EnableLetsEncrypt = false
  553. }
  554. LetsEncryptDirectory = sec.Key("LETSENCRYPT_DIRECTORY").MustString("https")
  555. LetsEncryptEmail = sec.Key("LETSENCRYPT_EMAIL").MustString("")
  556. Domain = sec.Key("DOMAIN").MustString("localhost")
  557. HTTPAddr = sec.Key("HTTP_ADDR").MustString("0.0.0.0")
  558. HTTPPort = sec.Key("HTTP_PORT").MustString("3000")
  559. GracefulRestartable = sec.Key("ALLOW_GRACEFUL_RESTARTS").MustBool(true)
  560. GracefulHammerTime = sec.Key("GRACEFUL_HAMMER_TIME").MustDuration(60 * time.Second)
  561. StartupTimeout = sec.Key("STARTUP_TIMEOUT").MustDuration(0 * time.Second)
  562. defaultAppURL := string(Protocol) + "://" + Domain
  563. if (Protocol == HTTP && HTTPPort != "80") || (Protocol == HTTPS && HTTPPort != "443") {
  564. defaultAppURL += ":" + HTTPPort
  565. }
  566. AppURL = sec.Key("ROOT_URL").MustString(defaultAppURL)
  567. AppURL = strings.TrimSuffix(AppURL, "/") + "/"
  568. // Check if has app suburl.
  569. appURL, err := url.Parse(AppURL)
  570. if err != nil {
  571. log.Fatal("Invalid ROOT_URL '%s': %s", AppURL, err)
  572. }
  573. // Suburl should start with '/' and end without '/', such as '/{subpath}'.
  574. // This value is empty if site does not have sub-url.
  575. AppSubURL = strings.TrimSuffix(appURL.Path, "/")
  576. StaticURLPrefix = strings.TrimSuffix(sec.Key("STATIC_URL_PREFIX").MustString(AppSubURL), "/")
  577. AppSubURLDepth = strings.Count(AppSubURL, "/")
  578. // Check if Domain differs from AppURL domain than update it to AppURL's domain
  579. // TODO: Can be replaced with url.Hostname() when minimal GoLang version is 1.8
  580. urlHostname := strings.SplitN(appURL.Host, ":", 2)[0]
  581. if urlHostname != Domain && net.ParseIP(urlHostname) == nil {
  582. Domain = urlHostname
  583. }
  584. var defaultLocalURL string
  585. switch Protocol {
  586. case UnixSocket:
  587. defaultLocalURL = "http://unix/"
  588. case FCGI:
  589. defaultLocalURL = AppURL
  590. case FCGIUnix:
  591. defaultLocalURL = AppURL
  592. default:
  593. defaultLocalURL = string(Protocol) + "://"
  594. if HTTPAddr == "0.0.0.0" {
  595. defaultLocalURL += "localhost"
  596. } else {
  597. defaultLocalURL += HTTPAddr
  598. }
  599. defaultLocalURL += ":" + HTTPPort + "/"
  600. }
  601. LocalURL = sec.Key("LOCAL_ROOT_URL").MustString(defaultLocalURL)
  602. RedirectOtherPort = sec.Key("REDIRECT_OTHER_PORT").MustBool(false)
  603. PortToRedirect = sec.Key("PORT_TO_REDIRECT").MustString("80")
  604. OfflineMode = sec.Key("OFFLINE_MODE").MustBool()
  605. DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool()
  606. StaticRootPath = sec.Key("STATIC_ROOT_PATH").MustString(AppWorkPath)
  607. StaticCacheTime = sec.Key("STATIC_CACHE_TIME").MustDuration(6 * time.Hour)
  608. AppDataPath = sec.Key("APP_DATA_PATH").MustString(path.Join(AppWorkPath, "data"))
  609. EnableGzip = sec.Key("ENABLE_GZIP").MustBool()
  610. EnablePprof = sec.Key("ENABLE_PPROF").MustBool(false)
  611. PprofDataPath = sec.Key("PPROF_DATA_PATH").MustString(path.Join(AppWorkPath, "data/tmp/pprof"))
  612. if !filepath.IsAbs(PprofDataPath) {
  613. PprofDataPath = filepath.Join(AppWorkPath, PprofDataPath)
  614. }
  615. switch sec.Key("LANDING_PAGE").MustString("home") {
  616. case "explore":
  617. LandingPageURL = LandingPageExplore
  618. case "organizations":
  619. LandingPageURL = LandingPageOrganizations
  620. case "login":
  621. LandingPageURL = LandingPageLogin
  622. default:
  623. LandingPageURL = LandingPageHome
  624. }
  625. if len(SSH.Domain) == 0 {
  626. SSH.Domain = Domain
  627. }
  628. SSH.RootPath = path.Join(homeDir, ".ssh")
  629. serverCiphers := sec.Key("SSH_SERVER_CIPHERS").Strings(",")
  630. if len(serverCiphers) > 0 {
  631. SSH.ServerCiphers = serverCiphers
  632. }
  633. serverKeyExchanges := sec.Key("SSH_SERVER_KEY_EXCHANGES").Strings(",")
  634. if len(serverKeyExchanges) > 0 {
  635. SSH.ServerKeyExchanges = serverKeyExchanges
  636. }
  637. serverMACs := sec.Key("SSH_SERVER_MACS").Strings(",")
  638. if len(serverMACs) > 0 {
  639. SSH.ServerMACs = serverMACs
  640. }
  641. SSH.KeyTestPath = os.TempDir()
  642. if err = Cfg.Section("server").MapTo(&SSH); err != nil {
  643. log.Fatal("Failed to map SSH settings: %v", err)
  644. }
  645. SSH.KeygenPath = sec.Key("SSH_KEYGEN_PATH").MustString("ssh-keygen")
  646. SSH.Port = sec.Key("SSH_PORT").MustInt(22)
  647. SSH.ListenPort = sec.Key("SSH_LISTEN_PORT").MustInt(SSH.Port)
  648. // When disable SSH, start builtin server value is ignored.
  649. if SSH.Disabled {
  650. SSH.StartBuiltinServer = false
  651. }
  652. if !SSH.Disabled && !SSH.StartBuiltinServer {
  653. if err := os.MkdirAll(SSH.RootPath, 0700); err != nil {
  654. log.Fatal("Failed to create '%s': %v", SSH.RootPath, err)
  655. } else if err = os.MkdirAll(SSH.KeyTestPath, 0644); err != nil {
  656. log.Fatal("Failed to create '%s': %v", SSH.KeyTestPath, err)
  657. }
  658. }
  659. SSH.MinimumKeySizeCheck = sec.Key("MINIMUM_KEY_SIZE_CHECK").MustBool()
  660. minimumKeySizes := Cfg.Section("ssh.minimum_key_sizes").Keys()
  661. for _, key := range minimumKeySizes {
  662. if key.MustInt() != -1 {
  663. SSH.MinimumKeySizes[strings.ToLower(key.Name())] = key.MustInt()
  664. }
  665. }
  666. SSH.AuthorizedKeysBackup = sec.Key("SSH_AUTHORIZED_KEYS_BACKUP").MustBool(true)
  667. SSH.CreateAuthorizedKeysFile = sec.Key("SSH_CREATE_AUTHORIZED_KEYS_FILE").MustBool(true)
  668. SSH.ExposeAnonymous = sec.Key("SSH_EXPOSE_ANONYMOUS").MustBool(false)
  669. sec = Cfg.Section("server")
  670. if err = sec.MapTo(&LFS); err != nil {
  671. log.Fatal("Failed to map LFS settings: %v", err)
  672. }
  673. LFS.ContentPath = sec.Key("LFS_CONTENT_PATH").MustString(filepath.Join(AppDataPath, "lfs"))
  674. if !filepath.IsAbs(LFS.ContentPath) {
  675. LFS.ContentPath = filepath.Join(AppWorkPath, LFS.ContentPath)
  676. }
  677. if LFS.LocksPagingNum == 0 {
  678. LFS.LocksPagingNum = 50
  679. }
  680. LFS.HTTPAuthExpiry = sec.Key("LFS_HTTP_AUTH_EXPIRY").MustDuration(20 * time.Minute)
  681. if LFS.StartServer {
  682. LFS.JWTSecretBytes = make([]byte, 32)
  683. n, err := base64.RawURLEncoding.Decode(LFS.JWTSecretBytes, []byte(LFS.JWTSecretBase64))
  684. if err != nil || n != 32 {
  685. LFS.JWTSecretBase64, err = generate.NewJwtSecret()
  686. if err != nil {
  687. log.Fatal("Error generating JWT Secret for custom config: %v", err)
  688. return
  689. }
  690. // Save secret
  691. cfg := ini.Empty()
  692. if com.IsFile(CustomConf) {
  693. // Keeps custom settings if there is already something.
  694. if err := cfg.Append(CustomConf); err != nil {
  695. log.Error("Failed to load custom conf '%s': %v", CustomConf, err)
  696. }
  697. }
  698. cfg.Section("server").Key("LFS_JWT_SECRET").SetValue(LFS.JWTSecretBase64)
  699. if err := os.MkdirAll(filepath.Dir(CustomConf), os.ModePerm); err != nil {
  700. log.Fatal("Failed to create '%s': %v", CustomConf, err)
  701. }
  702. if err := cfg.SaveTo(CustomConf); err != nil {
  703. log.Fatal("Error saving generated JWT Secret to custom config: %v", err)
  704. return
  705. }
  706. }
  707. }
  708. if err = Cfg.Section("oauth2").MapTo(&OAuth2); err != nil {
  709. log.Fatal("Failed to OAuth2 settings: %v", err)
  710. return
  711. }
  712. if OAuth2.Enable {
  713. OAuth2.JWTSecretBytes = make([]byte, 32)
  714. n, err := base64.RawURLEncoding.Decode(OAuth2.JWTSecretBytes, []byte(OAuth2.JWTSecretBase64))
  715. if err != nil || n != 32 {
  716. OAuth2.JWTSecretBase64, err = generate.NewJwtSecret()
  717. if err != nil {
  718. log.Fatal("error generating JWT secret: %v", err)
  719. return
  720. }
  721. cfg := ini.Empty()
  722. if com.IsFile(CustomConf) {
  723. if err := cfg.Append(CustomConf); err != nil {
  724. log.Error("failed to load custom conf %s: %v", CustomConf, err)
  725. return
  726. }
  727. }
  728. cfg.Section("oauth2").Key("JWT_SECRET").SetValue(OAuth2.JWTSecretBase64)
  729. if err := os.MkdirAll(filepath.Dir(CustomConf), os.ModePerm); err != nil {
  730. log.Fatal("failed to create '%s': %v", CustomConf, err)
  731. return
  732. }
  733. if err := cfg.SaveTo(CustomConf); err != nil {
  734. log.Fatal("error saving generating JWT secret to custom config: %v", err)
  735. return
  736. }
  737. }
  738. }
  739. sec = Cfg.Section("admin")
  740. Admin.DefaultEmailNotification = sec.Key("DEFAULT_EMAIL_NOTIFICATIONS").MustString("enabled")
  741. sec = Cfg.Section("security")
  742. InstallLock = sec.Key("INSTALL_LOCK").MustBool(false)
  743. SecretKey = sec.Key("SECRET_KEY").MustString("!#@FDEWREWR&*(")
  744. LogInRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt(7)
  745. CookieUserName = sec.Key("COOKIE_USERNAME").MustString("gitea_awesome")
  746. CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").MustString("gitea_incredible")
  747. ReverseProxyAuthUser = sec.Key("REVERSE_PROXY_AUTHENTICATION_USER").MustString("X-WEBAUTH-USER")
  748. ReverseProxyAuthEmail = sec.Key("REVERSE_PROXY_AUTHENTICATION_EMAIL").MustString("X-WEBAUTH-EMAIL")
  749. MinPasswordLength = sec.Key("MIN_PASSWORD_LENGTH").MustInt(6)
  750. ImportLocalPaths = sec.Key("IMPORT_LOCAL_PATHS").MustBool(false)
  751. DisableGitHooks = sec.Key("DISABLE_GIT_HOOKS").MustBool(false)
  752. OnlyAllowPushIfGiteaEnvironmentSet = sec.Key("ONLY_ALLOW_PUSH_IF_GITEA_ENVIRONMENT_SET").MustBool(true)
  753. PasswordHashAlgo = sec.Key("PASSWORD_HASH_ALGO").MustString("pbkdf2")
  754. CSRFCookieHTTPOnly = sec.Key("CSRF_COOKIE_HTTP_ONLY").MustBool(true)
  755. InternalToken = loadInternalToken(sec)
  756. cfgdata := sec.Key("PASSWORD_COMPLEXITY").Strings(",")
  757. PasswordComplexity = make([]string, 0, len(cfgdata))
  758. for _, name := range cfgdata {
  759. name := strings.ToLower(strings.Trim(name, `"`))
  760. if name != "" {
  761. PasswordComplexity = append(PasswordComplexity, name)
  762. }
  763. }
  764. sec = Cfg.Section("attachment")
  765. AttachmentPath = sec.Key("PATH").MustString(path.Join(AppDataPath, "attachments"))
  766. if !filepath.IsAbs(AttachmentPath) {
  767. AttachmentPath = path.Join(AppWorkPath, AttachmentPath)
  768. }
  769. AttachmentAllowedTypes = strings.Replace(sec.Key("ALLOWED_TYPES").MustString("image/jpeg,image/png,application/zip,application/gzip"), "|", ",", -1)
  770. AttachmentMaxSize = sec.Key("MAX_SIZE").MustInt64(4)
  771. AttachmentMaxFiles = sec.Key("MAX_FILES").MustInt(5)
  772. AttachmentEnabled = sec.Key("ENABLED").MustBool(true)
  773. timeFormatKey := Cfg.Section("time").Key("FORMAT").MustString("")
  774. if timeFormatKey != "" {
  775. TimeFormat = map[string]string{
  776. "ANSIC": time.ANSIC,
  777. "UnixDate": time.UnixDate,
  778. "RubyDate": time.RubyDate,
  779. "RFC822": time.RFC822,
  780. "RFC822Z": time.RFC822Z,
  781. "RFC850": time.RFC850,
  782. "RFC1123": time.RFC1123,
  783. "RFC1123Z": time.RFC1123Z,
  784. "RFC3339": time.RFC3339,
  785. "RFC3339Nano": time.RFC3339Nano,
  786. "Kitchen": time.Kitchen,
  787. "Stamp": time.Stamp,
  788. "StampMilli": time.StampMilli,
  789. "StampMicro": time.StampMicro,
  790. "StampNano": time.StampNano,
  791. }[timeFormatKey]
  792. // When the TimeFormatKey does not exist in the previous map e.g.'2006-01-02 15:04:05'
  793. if len(TimeFormat) == 0 {
  794. TimeFormat = timeFormatKey
  795. TestTimeFormat, _ := time.Parse(TimeFormat, TimeFormat)
  796. if TestTimeFormat.Format(time.RFC3339) != "2006-01-02T15:04:05Z" {
  797. log.Warn("Provided TimeFormat: %s does not create a fully specified date and time.", TimeFormat)
  798. log.Warn("In order to display dates and times correctly please check your time format has 2006, 01, 02, 15, 04 and 05")
  799. }
  800. log.Trace("Custom TimeFormat: %s", TimeFormat)
  801. }
  802. }
  803. zone := Cfg.Section("time").Key("DEFAULT_UI_LOCATION").String()
  804. if zone != "" {
  805. DefaultUILocation, err = time.LoadLocation(zone)
  806. if err != nil {
  807. log.Fatal("Load time zone failed: %v", err)
  808. } else {
  809. log.Info("Default UI Location is %v", zone)
  810. }
  811. }
  812. if DefaultUILocation == nil {
  813. DefaultUILocation = time.Local
  814. }
  815. RunUser = Cfg.Section("").Key("RUN_USER").MustString(user.CurrentUsername())
  816. // Does not check run user when the install lock is off.
  817. if InstallLock {
  818. currentUser, match := IsRunUserMatchCurrentUser(RunUser)
  819. if !match {
  820. log.Fatal("Expect user '%s' but current user is: %s", RunUser, currentUser)
  821. }
  822. }
  823. SSH.BuiltinServerUser = Cfg.Section("server").Key("BUILTIN_SSH_SERVER_USER").MustString(RunUser)
  824. newRepository()
  825. sec = Cfg.Section("picture")
  826. AvatarUploadPath = sec.Key("AVATAR_UPLOAD_PATH").MustString(path.Join(AppDataPath, "avatars"))
  827. forcePathSeparator(AvatarUploadPath)
  828. if !filepath.IsAbs(AvatarUploadPath) {
  829. AvatarUploadPath = path.Join(AppWorkPath, AvatarUploadPath)
  830. }
  831. RepositoryAvatarUploadPath = sec.Key("REPOSITORY_AVATAR_UPLOAD_PATH").MustString(path.Join(AppDataPath, "repo-avatars"))
  832. forcePathSeparator(RepositoryAvatarUploadPath)
  833. if !filepath.IsAbs(RepositoryAvatarUploadPath) {
  834. RepositoryAvatarUploadPath = path.Join(AppWorkPath, RepositoryAvatarUploadPath)
  835. }
  836. RepositoryAvatarFallback = sec.Key("REPOSITORY_AVATAR_FALLBACK").MustString("none")
  837. RepositoryAvatarFallbackImage = sec.Key("REPOSITORY_AVATAR_FALLBACK_IMAGE").MustString("/img/repo_default.png")
  838. AvatarMaxWidth = sec.Key("AVATAR_MAX_WIDTH").MustInt(4096)
  839. AvatarMaxHeight = sec.Key("AVATAR_MAX_HEIGHT").MustInt(3072)
  840. AvatarMaxFileSize = sec.Key("AVATAR_MAX_FILE_SIZE").MustInt64(1048576)
  841. switch source := sec.Key("GRAVATAR_SOURCE").MustString("gravatar"); source {
  842. case "duoshuo":
  843. GravatarSource = "http://gravatar.duoshuo.com/avatar/"
  844. case "gravatar":
  845. GravatarSource = "https://secure.gravatar.com/avatar/"
  846. case "libravatar":
  847. GravatarSource = "https://seccdn.libravatar.org/avatar/"
  848. default:
  849. GravatarSource = source
  850. }
  851. DisableGravatar = sec.Key("DISABLE_GRAVATAR").MustBool()
  852. EnableFederatedAvatar = sec.Key("ENABLE_FEDERATED_AVATAR").MustBool(!InstallLock)
  853. if OfflineMode {
  854. DisableGravatar = true
  855. EnableFederatedAvatar = false
  856. }
  857. if DisableGravatar {
  858. EnableFederatedAvatar = false
  859. }
  860. if EnableFederatedAvatar || !DisableGravatar {
  861. GravatarSourceURL, err = url.Parse(GravatarSource)
  862. if err != nil {
  863. log.Fatal("Failed to parse Gravatar URL(%s): %v",
  864. GravatarSource, err)
  865. }
  866. }
  867. if EnableFederatedAvatar {
  868. LibravatarService = libravatar.New()
  869. if GravatarSourceURL.Scheme == "https" {
  870. LibravatarService.SetUseHTTPS(true)
  871. LibravatarService.SetSecureFallbackHost(GravatarSourceURL.Host)
  872. } else {
  873. LibravatarService.SetUseHTTPS(false)
  874. LibravatarService.SetFallbackHost(GravatarSourceURL.Host)
  875. }
  876. }
  877. if err = Cfg.Section("ui").MapTo(&UI); err != nil {
  878. log.Fatal("Failed to map UI settings: %v", err)
  879. } else if err = Cfg.Section("markdown").MapTo(&Markdown); err != nil {
  880. log.Fatal("Failed to map Markdown settings: %v", err)
  881. } else if err = Cfg.Section("admin").MapTo(&Admin); err != nil {
  882. log.Fatal("Fail to map Admin settings: %v", err)
  883. } else if err = Cfg.Section("api").MapTo(&API); err != nil {
  884. log.Fatal("Failed to map API settings: %v", err)
  885. } else if err = Cfg.Section("metrics").MapTo(&Metrics); err != nil {
  886. log.Fatal("Failed to map Metrics settings: %v", err)
  887. }
  888. u := *appURL
  889. u.Path = path.Join(u.Path, "api", "swagger")
  890. API.SwaggerURL = u.String()
  891. newGit()
  892. sec = Cfg.Section("mirror")
  893. Mirror.MinInterval = sec.Key("MIN_INTERVAL").MustDuration(10 * time.Minute)
  894. Mirror.DefaultInterval = sec.Key("DEFAULT_INTERVAL").MustDuration(8 * time.Hour)
  895. if Mirror.MinInterval.Minutes() < 1 {
  896. log.Warn("Mirror.MinInterval is too low")
  897. Mirror.MinInterval = 1 * time.Minute
  898. }
  899. if Mirror.DefaultInterval < Mirror.MinInterval {
  900. log.Warn("Mirror.DefaultInterval is less than Mirror.MinInterval")
  901. Mirror.DefaultInterval = time.Hour * 8
  902. }
  903. Langs = Cfg.Section("i18n").Key("LANGS").Strings(",")
  904. if len(Langs) == 0 {
  905. Langs = []string{
  906. "en-US", "zh-CN", "zh-HK", "zh-TW", "de-DE", "fr-FR", "nl-NL", "lv-LV",
  907. "ru-RU", "uk-UA", "ja-JP", "es-ES", "pt-BR", "pl-PL", "bg-BG", "it-IT",
  908. "fi-FI", "tr-TR", "cs-CZ", "sr-SP", "sv-SE", "ko-KR"}
  909. }
  910. Names = Cfg.Section("i18n").Key("NAMES").Strings(",")
  911. if len(Names) == 0 {
  912. Names = []string{"English", "简体中文", "繁體中文(香港)", "繁體中文(台灣)", "Deutsch",
  913. "français", "Nederlands", "latviešu", "русский", "Українська", "日本語",
  914. "español", "português do Brasil", "polski", "български", "italiano",
  915. "suomi", "Türkçe", "čeština", "српски", "svenska", "한국어"}
  916. }
  917. dateLangs = Cfg.Section("i18n.datelang").KeysHash()
  918. ShowFooterBranding = Cfg.Section("other").Key("SHOW_FOOTER_BRANDING").MustBool(false)
  919. ShowFooterVersion = Cfg.Section("other").Key("SHOW_FOOTER_VERSION").MustBool(true)
  920. ShowFooterTemplateLoadTime = Cfg.Section("other").Key("SHOW_FOOTER_TEMPLATE_LOAD_TIME").MustBool(true)
  921. UI.ShowUserEmail = Cfg.Section("ui").Key("SHOW_USER_EMAIL").MustBool(true)
  922. UI.DefaultShowFullName = Cfg.Section("ui").Key("DEFAULT_SHOW_FULL_NAME").MustBool(false)
  923. UI.SearchRepoDescription = Cfg.Section("ui").Key("SEARCH_REPO_DESCRIPTION").MustBool(true)
  924. UI.UseServiceWorker = Cfg.Section("ui").Key("USE_SERVICE_WORKER").MustBool(true)
  925. HasRobotsTxt = com.IsFile(path.Join(CustomPath, "robots.txt"))
  926. newMarkup()
  927. sec = Cfg.Section("U2F")
  928. U2F.TrustedFacets, _ = shellquote.Split(sec.Key("TRUSTED_FACETS").MustString(strings.TrimRight(AppURL, "/")))
  929. U2F.AppID = sec.Key("APP_ID").MustString(strings.TrimRight(AppURL, "/"))
  930. zip.Verbose = false
  931. UI.ReactionsMap = make(map[string]bool)
  932. for _, reaction := range UI.Reactions {
  933. UI.ReactionsMap[reaction] = true
  934. }
  935. }
  936. func loadInternalToken(sec *ini.Section) string {
  937. uri := sec.Key("INTERNAL_TOKEN_URI").String()
  938. if len(uri) == 0 {
  939. return loadOrGenerateInternalToken(sec)
  940. }
  941. tempURI, err := url.Parse(uri)
  942. if err != nil {
  943. log.Fatal("Failed to parse INTERNAL_TOKEN_URI (%s): %v", uri, err)
  944. }
  945. switch tempURI.Scheme {
  946. case "file":
  947. fp, err := os.OpenFile(tempURI.RequestURI(), os.O_RDWR, 0600)
  948. if err != nil {
  949. log.Fatal("Failed to open InternalTokenURI (%s): %v", uri, err)
  950. }
  951. defer fp.Close()
  952. buf, err := ioutil.ReadAll(fp)
  953. if err != nil {
  954. log.Fatal("Failed to read InternalTokenURI (%s): %v", uri, err)
  955. }
  956. // No token in the file, generate one and store it.
  957. if len(buf) == 0 {
  958. token, err := generate.NewInternalToken()
  959. if err != nil {
  960. log.Fatal("Error generate internal token: %v", err)
  961. }
  962. if _, err := io.WriteString(fp, token); err != nil {
  963. log.Fatal("Error writing to InternalTokenURI (%s): %v", uri, err)
  964. }
  965. return token
  966. }
  967. return string(buf)
  968. default:
  969. log.Fatal("Unsupported URI-Scheme %q (INTERNAL_TOKEN_URI = %q)", tempURI.Scheme, uri)
  970. }
  971. return ""
  972. }
  973. func loadOrGenerateInternalToken(sec *ini.Section) string {
  974. var err error
  975. token := sec.Key("INTERNAL_TOKEN").String()
  976. if len(token) == 0 {
  977. token, err = generate.NewInternalToken()
  978. if err != nil {
  979. log.Fatal("Error generate internal token: %v", err)
  980. }
  981. // Save secret
  982. cfgSave := ini.Empty()
  983. if com.IsFile(CustomConf) {
  984. // Keeps custom settings if there is already something.
  985. if err := cfgSave.Append(CustomConf); err != nil {
  986. log.Error("Failed to load custom conf '%s': %v", CustomConf, err)
  987. }
  988. }
  989. cfgSave.Section("security").Key("INTERNAL_TOKEN").SetValue(token)
  990. if err := os.MkdirAll(filepath.Dir(CustomConf), os.ModePerm); err != nil {
  991. log.Fatal("Failed to create '%s': %v", CustomConf, err)
  992. }
  993. if err := cfgSave.SaveTo(CustomConf); err != nil {
  994. log.Fatal("Error saving generated INTERNAL_TOKEN to custom config: %v", err)
  995. }
  996. }
  997. return token
  998. }
  999. func ensureLFSDirectory() {
  1000. if LFS.StartServer {
  1001. if err := os.MkdirAll(LFS.ContentPath, 0700); err != nil {
  1002. log.Fatal("Failed to create '%s': %v", LFS.ContentPath, err)
  1003. }
  1004. }
  1005. }
  1006. // NewServices initializes the services
  1007. func NewServices() {
  1008. InitDBConfig()
  1009. newService()
  1010. NewLogServices(false)
  1011. ensureLFSDirectory()
  1012. newCacheService()
  1013. newSessionService()
  1014. newCORSService()
  1015. newMailService()
  1016. newRegisterMailService()
  1017. newNotifyMailService()
  1018. newWebhookService()
  1019. newMigrationsService()
  1020. newIndexerService()
  1021. newTaskService()
  1022. NewQueueService()
  1023. }