conf.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package conf
  5. import (
  6. "fmt"
  7. "net/mail"
  8. "net/url"
  9. "os"
  10. "path"
  11. "path/filepath"
  12. "strconv"
  13. "strings"
  14. "time"
  15. _ "github.com/go-macaron/cache/memcache"
  16. _ "github.com/go-macaron/cache/redis"
  17. "github.com/go-macaron/session"
  18. _ "github.com/go-macaron/session/redis"
  19. "github.com/mcuadros/go-version"
  20. "github.com/pkg/errors"
  21. "gopkg.in/ini.v1"
  22. log "unknwon.dev/clog/v2"
  23. "github.com/gogs/go-libravatar"
  24. "gogs.io/gogs/internal/assets/conf"
  25. "gogs.io/gogs/internal/osutil"
  26. )
  27. func init() {
  28. // Initialize the primary logger until logging service is up.
  29. err := log.NewConsole()
  30. if err != nil {
  31. panic("init console logger: " + err.Error())
  32. }
  33. }
  34. // Asset is a wrapper for getting conf assets.
  35. func Asset(name string) ([]byte, error) {
  36. return conf.Asset(name)
  37. }
  38. // AssetDir is a wrapper for getting conf assets.
  39. func AssetDir(name string) ([]string, error) {
  40. return conf.AssetDir(name)
  41. }
  42. // MustAsset is a wrapper for getting conf assets.
  43. func MustAsset(name string) []byte {
  44. return conf.MustAsset(name)
  45. }
  46. // File is the configuration object.
  47. var File *ini.File
  48. // Init initializes configuration from conf assets and given custom configuration file.
  49. // If `customConf` is empty, it falls back to default location, i.e. "<WORK DIR>/custom".
  50. // It is safe to call this function multiple times with desired `customConf`, but it is
  51. // not concurrent safe.
  52. //
  53. // ⚠️ WARNING: Do not print anything in this function other than wanrings.
  54. func Init(customConf string) error {
  55. var err error
  56. File, err = ini.LoadSources(ini.LoadOptions{
  57. IgnoreInlineComment: true,
  58. }, conf.MustAsset("conf/app.ini"))
  59. if err != nil {
  60. return errors.Wrap(err, "parse 'conf/app.ini'")
  61. }
  62. File.NameMapper = ini.SnackCase
  63. if customConf == "" {
  64. customConf = filepath.Join(CustomDir(), "conf", "app.ini")
  65. } else {
  66. customConf, err = filepath.Abs(customConf)
  67. if err != nil {
  68. return errors.Wrap(err, "get absolute path")
  69. }
  70. }
  71. CustomConf = customConf
  72. if osutil.IsFile(customConf) {
  73. if err = File.Append(customConf); err != nil {
  74. return errors.Wrapf(err, "append %q", customConf)
  75. }
  76. } else {
  77. log.Warn("Custom config %q not found. Ignore this warning if you're running for the first time", customConf)
  78. }
  79. if err = File.Section(ini.DefaultSection).MapTo(&App); err != nil {
  80. return errors.Wrap(err, "mapping default section")
  81. }
  82. // ***************************
  83. // ----- Server settings -----
  84. // ***************************
  85. if err = File.Section("server").MapTo(&Server); err != nil {
  86. return errors.Wrap(err, "mapping [server] section")
  87. }
  88. Server.AppDataPath = ensureAbs(Server.AppDataPath)
  89. if !strings.HasSuffix(Server.ExternalURL, "/") {
  90. Server.ExternalURL += "/"
  91. }
  92. Server.URL, err = url.Parse(Server.ExternalURL)
  93. if err != nil {
  94. return errors.Wrapf(err, "parse '[server] EXTERNAL_URL' %q", err)
  95. }
  96. // Subpath should start with '/' and end without '/', i.e. '/{subpath}'.
  97. Server.Subpath = strings.TrimRight(Server.URL.Path, "/")
  98. Server.SubpathDepth = strings.Count(Server.Subpath, "/")
  99. unixSocketMode, err := strconv.ParseUint(Server.UnixSocketPermission, 8, 32)
  100. if err != nil {
  101. return errors.Wrapf(err, "parse '[server] UNIX_SOCKET_PERMISSION' %q", Server.UnixSocketPermission)
  102. }
  103. if unixSocketMode > 0777 {
  104. unixSocketMode = 0666
  105. }
  106. Server.UnixSocketMode = os.FileMode(unixSocketMode)
  107. // ************************
  108. // ----- SSH settings -----
  109. // ************************
  110. SSH.RootPath = filepath.Join(HomeDir(), ".ssh")
  111. SSH.KeyTestPath = os.TempDir()
  112. if err = File.Section("server").MapTo(&SSH); err != nil {
  113. return errors.Wrap(err, "mapping SSH settings from [server] section")
  114. }
  115. SSH.RootPath = ensureAbs(SSH.RootPath)
  116. SSH.KeyTestPath = ensureAbs(SSH.KeyTestPath)
  117. if !SSH.Disabled {
  118. if !SSH.StartBuiltinServer {
  119. if err := os.MkdirAll(SSH.RootPath, 0700); err != nil {
  120. return errors.Wrap(err, "create SSH root directory")
  121. } else if err = os.MkdirAll(SSH.KeyTestPath, 0644); err != nil {
  122. return errors.Wrap(err, "create SSH key test directory")
  123. }
  124. } else {
  125. SSH.RewriteAuthorizedKeysAtStart = false
  126. }
  127. // Check if server is eligible for minimum key size check when user choose to enable.
  128. // Windows server and OpenSSH version lower than 5.1 are forced to be disabled because
  129. // the "ssh-keygen" in Windows does not print key type.
  130. // See https://github.com/gogs/gogs/issues/4507.
  131. if SSH.MinimumKeySizeCheck {
  132. sshVersion, err := openSSHVersion()
  133. if err != nil {
  134. return errors.Wrap(err, "get OpenSSH version")
  135. }
  136. if IsWindowsRuntime() || version.Compare(sshVersion, "5.1", "<") {
  137. log.Warn(`SSH minimum key size check is forced to be disabled because server is not eligible:
  138. 1. Windows server
  139. 2. OpenSSH version is lower than 5.1`)
  140. } else {
  141. SSH.MinimumKeySizes = map[string]int{}
  142. for _, key := range File.Section("ssh.minimum_key_sizes").Keys() {
  143. if key.MustInt() != -1 {
  144. SSH.MinimumKeySizes[strings.ToLower(key.Name())] = key.MustInt()
  145. }
  146. }
  147. }
  148. }
  149. }
  150. // *******************************
  151. // ----- Repository settings -----
  152. // *******************************
  153. Repository.Root = filepath.Join(HomeDir(), "gogs-repositories")
  154. if err = File.Section("repository").MapTo(&Repository); err != nil {
  155. return errors.Wrap(err, "mapping [repository] section")
  156. }
  157. Repository.Root = ensureAbs(Repository.Root)
  158. Repository.Upload.TempPath = ensureAbs(Repository.Upload.TempPath)
  159. // *******************************
  160. // ----- Database settings -----
  161. // *******************************
  162. if err = File.Section("database").MapTo(&Database); err != nil {
  163. return errors.Wrap(err, "mapping [database] section")
  164. }
  165. Database.Path = ensureAbs(Database.Path)
  166. // *******************************
  167. // ----- Security settings -----
  168. // *******************************
  169. if err = File.Section("security").MapTo(&Security); err != nil {
  170. return errors.Wrap(err, "mapping [security] section")
  171. }
  172. // Check run user when the install is locked.
  173. if Security.InstallLock {
  174. currentUser, match := CheckRunUser(App.RunUser)
  175. if !match {
  176. return fmt.Errorf("user configured to run Gogs is %q, but the current user is %q", App.RunUser, currentUser)
  177. }
  178. }
  179. // **************************
  180. // ----- Email settings -----
  181. // **************************
  182. if err = File.Section("email").MapTo(&Email); err != nil {
  183. return errors.Wrap(err, "mapping [email] section")
  184. }
  185. // LEGACY [0.13]: In case there are values with old section name.
  186. if err = File.Section("mailer").MapTo(&Email); err != nil {
  187. return errors.Wrap(err, "mapping [mailer] section")
  188. }
  189. if Email.Enabled {
  190. if Email.From == "" {
  191. Email.From = Email.User
  192. }
  193. parsed, err := mail.ParseAddress(Email.From)
  194. if err != nil {
  195. return errors.Wrapf(err, "parse mail address %q", Email.From)
  196. }
  197. Email.FromEmail = parsed.Address
  198. }
  199. handleDeprecated()
  200. // TODO
  201. sec := File.Section("attachment")
  202. AttachmentPath = sec.Key("PATH").MustString(filepath.Join(Server.AppDataPath, "attachments"))
  203. if !filepath.IsAbs(AttachmentPath) {
  204. AttachmentPath = path.Join(workDir, AttachmentPath)
  205. }
  206. AttachmentAllowedTypes = strings.Replace(sec.Key("ALLOWED_TYPES").MustString("image/jpeg,image/png"), "|", ",", -1)
  207. AttachmentMaxSize = sec.Key("MAX_SIZE").MustInt64(4)
  208. AttachmentMaxFiles = sec.Key("MAX_FILES").MustInt(5)
  209. AttachmentEnabled = sec.Key("ENABLED").MustBool(true)
  210. TimeFormat = map[string]string{
  211. "ANSIC": time.ANSIC,
  212. "UnixDate": time.UnixDate,
  213. "RubyDate": time.RubyDate,
  214. "RFC822": time.RFC822,
  215. "RFC822Z": time.RFC822Z,
  216. "RFC850": time.RFC850,
  217. "RFC1123": time.RFC1123,
  218. "RFC1123Z": time.RFC1123Z,
  219. "RFC3339": time.RFC3339,
  220. "RFC3339Nano": time.RFC3339Nano,
  221. "Kitchen": time.Kitchen,
  222. "Stamp": time.Stamp,
  223. "StampMilli": time.StampMilli,
  224. "StampMicro": time.StampMicro,
  225. "StampNano": time.StampNano,
  226. }[File.Section("time").Key("FORMAT").MustString("RFC1123")]
  227. sec = File.Section("picture")
  228. AvatarUploadPath = sec.Key("AVATAR_UPLOAD_PATH").MustString(filepath.Join(Server.AppDataPath, "avatars"))
  229. if !filepath.IsAbs(AvatarUploadPath) {
  230. AvatarUploadPath = path.Join(workDir, AvatarUploadPath)
  231. }
  232. RepositoryAvatarUploadPath = sec.Key("REPOSITORY_AVATAR_UPLOAD_PATH").MustString(filepath.Join(Server.AppDataPath, "repo-avatars"))
  233. if !filepath.IsAbs(RepositoryAvatarUploadPath) {
  234. RepositoryAvatarUploadPath = path.Join(workDir, RepositoryAvatarUploadPath)
  235. }
  236. switch source := sec.Key("GRAVATAR_SOURCE").MustString("gravatar"); source {
  237. case "duoshuo":
  238. GravatarSource = "http://gravatar.duoshuo.com/avatar/"
  239. case "gravatar":
  240. GravatarSource = "https://secure.gravatar.com/avatar/"
  241. case "libravatar":
  242. GravatarSource = "https://seccdn.libravatar.org/avatar/"
  243. default:
  244. GravatarSource = source
  245. }
  246. DisableGravatar = sec.Key("DISABLE_GRAVATAR").MustBool()
  247. EnableFederatedAvatar = sec.Key("ENABLE_FEDERATED_AVATAR").MustBool(true)
  248. if Server.OfflineMode {
  249. DisableGravatar = true
  250. EnableFederatedAvatar = false
  251. }
  252. if DisableGravatar {
  253. EnableFederatedAvatar = false
  254. }
  255. if EnableFederatedAvatar {
  256. LibravatarService = libravatar.New()
  257. parts := strings.Split(GravatarSource, "/")
  258. if len(parts) >= 3 {
  259. if parts[0] == "https:" {
  260. LibravatarService.SetUseHTTPS(true)
  261. LibravatarService.SetSecureFallbackHost(parts[2])
  262. } else {
  263. LibravatarService.SetUseHTTPS(false)
  264. LibravatarService.SetFallbackHost(parts[2])
  265. }
  266. }
  267. }
  268. if err = File.Section("http").MapTo(&HTTP); err != nil {
  269. log.Fatal("Failed to map HTTP settings: %v", err)
  270. } else if err = File.Section("webhook").MapTo(&Webhook); err != nil {
  271. log.Fatal("Failed to map Webhook settings: %v", err)
  272. } else if err = File.Section("release.attachment").MapTo(&Release.Attachment); err != nil {
  273. log.Fatal("Failed to map Release.Attachment settings: %v", err)
  274. } else if err = File.Section("markdown").MapTo(&Markdown); err != nil {
  275. log.Fatal("Failed to map Markdown settings: %v", err)
  276. } else if err = File.Section("smartypants").MapTo(&Smartypants); err != nil {
  277. log.Fatal("Failed to map Smartypants settings: %v", err)
  278. } else if err = File.Section("admin").MapTo(&Admin); err != nil {
  279. log.Fatal("Failed to map Admin settings: %v", err)
  280. } else if err = File.Section("cron").MapTo(&Cron); err != nil {
  281. log.Fatal("Failed to map Cron settings: %v", err)
  282. } else if err = File.Section("git").MapTo(&Git); err != nil {
  283. log.Fatal("Failed to map Git settings: %v", err)
  284. } else if err = File.Section("mirror").MapTo(&Mirror); err != nil {
  285. log.Fatal("Failed to map Mirror settings: %v", err)
  286. } else if err = File.Section("api").MapTo(&API); err != nil {
  287. log.Fatal("Failed to map API settings: %v", err)
  288. } else if err = File.Section("ui").MapTo(&UI); err != nil {
  289. log.Fatal("Failed to map UI settings: %v", err)
  290. } else if err = File.Section("prometheus").MapTo(&Prometheus); err != nil {
  291. log.Fatal("Failed to map Prometheus settings: %v", err)
  292. }
  293. if Mirror.DefaultInterval <= 0 {
  294. Mirror.DefaultInterval = 24
  295. }
  296. Langs = File.Section("i18n").Key("LANGS").Strings(",")
  297. Names = File.Section("i18n").Key("NAMES").Strings(",")
  298. dateLangs = File.Section("i18n.datelang").KeysHash()
  299. ShowFooterBranding = File.Section("other").Key("SHOW_FOOTER_BRANDING").MustBool()
  300. ShowFooterTemplateLoadTime = File.Section("other").Key("SHOW_FOOTER_TEMPLATE_LOAD_TIME").MustBool()
  301. HasRobotsTxt = osutil.IsFile(path.Join(CustomDir(), "robots.txt"))
  302. return nil
  303. }
  304. // MustInit panics if configuration initialization failed.
  305. func MustInit(customConf string) {
  306. err := Init(customConf)
  307. if err != nil {
  308. panic(err)
  309. }
  310. }
  311. // TODO
  312. var (
  313. HTTP struct {
  314. AccessControlAllowOrigin string
  315. }
  316. // Database settings
  317. UseSQLite3 bool
  318. UseMySQL bool
  319. UsePostgreSQL bool
  320. UseMSSQL bool
  321. // Webhook settings
  322. Webhook struct {
  323. Types []string
  324. QueueLength int
  325. DeliverTimeout int
  326. SkipTLSVerify bool `ini:"SKIP_TLS_VERIFY"`
  327. PagingNum int
  328. }
  329. // Release settigns
  330. Release struct {
  331. Attachment struct {
  332. Enabled bool
  333. TempPath string
  334. AllowedTypes []string `delim:"|"`
  335. MaxSize int64
  336. MaxFiles int
  337. } `ini:"-"`
  338. }
  339. // Markdown sttings
  340. Markdown struct {
  341. EnableHardLineBreak bool
  342. CustomURLSchemes []string `ini:"CUSTOM_URL_SCHEMES"`
  343. FileExtensions []string
  344. }
  345. // Smartypants settings
  346. Smartypants struct {
  347. Enabled bool
  348. Fractions bool
  349. Dashes bool
  350. LatexDashes bool
  351. AngledQuotes bool
  352. }
  353. // Admin settings
  354. Admin struct {
  355. DisableRegularOrgCreation bool
  356. }
  357. // Picture settings
  358. AvatarUploadPath string
  359. RepositoryAvatarUploadPath string
  360. GravatarSource string
  361. DisableGravatar bool
  362. EnableFederatedAvatar bool
  363. LibravatarService *libravatar.Libravatar
  364. // Log settings
  365. LogRootPath string
  366. LogModes []string
  367. LogConfigs []interface{}
  368. // Attachment settings
  369. AttachmentPath string
  370. AttachmentAllowedTypes string
  371. AttachmentMaxSize int64
  372. AttachmentMaxFiles int
  373. AttachmentEnabled bool
  374. // Time settings
  375. TimeFormat string
  376. // Cache settings
  377. CacheAdapter string
  378. CacheInterval int
  379. CacheConn string
  380. // Session settings
  381. SessionConfig session.Options
  382. CSRFCookieName string
  383. // Cron tasks
  384. Cron struct {
  385. UpdateMirror struct {
  386. Enabled bool
  387. RunAtStart bool
  388. Schedule string
  389. } `ini:"cron.update_mirrors"`
  390. RepoHealthCheck struct {
  391. Enabled bool
  392. RunAtStart bool
  393. Schedule string
  394. Timeout time.Duration
  395. Args []string `delim:" "`
  396. } `ini:"cron.repo_health_check"`
  397. CheckRepoStats struct {
  398. Enabled bool
  399. RunAtStart bool
  400. Schedule string
  401. } `ini:"cron.check_repo_stats"`
  402. RepoArchiveCleanup struct {
  403. Enabled bool
  404. RunAtStart bool
  405. Schedule string
  406. OlderThan time.Duration
  407. } `ini:"cron.repo_archive_cleanup"`
  408. }
  409. // Git settings
  410. Git struct {
  411. Version string `ini:"-"`
  412. DisableDiffHighlight bool
  413. MaxGitDiffLines int
  414. MaxGitDiffLineCharacters int
  415. MaxGitDiffFiles int
  416. GCArgs []string `ini:"GC_ARGS" delim:" "`
  417. Timeout struct {
  418. Migrate int
  419. Mirror int
  420. Clone int
  421. Pull int
  422. GC int `ini:"GC"`
  423. } `ini:"git.timeout"`
  424. }
  425. // Mirror settings
  426. Mirror struct {
  427. DefaultInterval int
  428. }
  429. // API settings
  430. API struct {
  431. MaxResponseItems int
  432. }
  433. // UI settings
  434. UI struct {
  435. ExplorePagingNum int
  436. IssuePagingNum int
  437. FeedMaxCommitNum int
  438. ThemeColorMetaTag string
  439. MaxDisplayFileSize int64
  440. Admin struct {
  441. UserPagingNum int
  442. RepoPagingNum int
  443. NoticePagingNum int
  444. OrgPagingNum int
  445. } `ini:"ui.admin"`
  446. User struct {
  447. RepoPagingNum int
  448. NewsFeedPagingNum int
  449. CommitsPagingNum int
  450. } `ini:"ui.user"`
  451. }
  452. // Prometheus settings
  453. Prometheus struct {
  454. Enabled bool
  455. EnableBasicAuth bool
  456. BasicAuthUsername string
  457. BasicAuthPassword string
  458. }
  459. // I18n settings
  460. Langs []string
  461. Names []string
  462. dateLangs map[string]string
  463. // Highlight settings are loaded in modules/template/hightlight.go
  464. // Other settings
  465. ShowFooterBranding bool
  466. ShowFooterTemplateLoadTime bool
  467. // Global setting objects
  468. HasRobotsTxt bool
  469. )
  470. // DateLang transforms standard language locale name to corresponding value in datetime plugin.
  471. func DateLang(lang string) string {
  472. name, ok := dateLangs[lang]
  473. if ok {
  474. return name
  475. }
  476. return "en"
  477. }
  478. // InitLogging initializes the logging service of the application.
  479. func InitLogging() {
  480. LogRootPath = File.Section("log").Key("ROOT_PATH").MustString(filepath.Join(WorkDir(), "log"))
  481. // Because we always create a console logger as the primary logger at init time,
  482. // we need to remove it in case the user doesn't configure to use it after the
  483. // logging service is initalized.
  484. hasConsole := false
  485. // Iterate over [log.*] sections to initialize individual logger.
  486. LogModes = strings.Split(File.Section("log").Key("MODE").MustString("console"), ",")
  487. LogConfigs = make([]interface{}, len(LogModes))
  488. levelMappings := map[string]log.Level{
  489. "trace": log.LevelTrace,
  490. "info": log.LevelInfo,
  491. "warn": log.LevelWarn,
  492. "error": log.LevelError,
  493. "fatal": log.LevelFatal,
  494. }
  495. type config struct {
  496. Buffer int64
  497. Config interface{}
  498. }
  499. for i, mode := range LogModes {
  500. mode = strings.ToLower(strings.TrimSpace(mode))
  501. secName := "log." + mode
  502. sec, err := File.GetSection(secName)
  503. if err != nil {
  504. log.Fatal("Missing configuration section [%s] for %q logger", secName, mode)
  505. return
  506. }
  507. level := levelMappings[strings.ToLower(sec.Key("LEVEL").MustString("trace"))]
  508. buffer := sec.Key("BUFFER_LEN").MustInt64(100)
  509. c := new(config)
  510. switch mode {
  511. case log.DefaultConsoleName:
  512. hasConsole = true
  513. c = &config{
  514. Buffer: buffer,
  515. Config: log.ConsoleConfig{
  516. Level: level,
  517. },
  518. }
  519. err = log.NewConsole(c.Buffer, c.Config)
  520. case log.DefaultFileName:
  521. logPath := filepath.Join(LogRootPath, "gogs.log")
  522. logDir := filepath.Dir(logPath)
  523. err = os.MkdirAll(logDir, os.ModePerm)
  524. if err != nil {
  525. log.Fatal("Failed to create log directory %q: %v", logDir, err)
  526. return
  527. }
  528. c = &config{
  529. Buffer: buffer,
  530. Config: log.FileConfig{
  531. Level: level,
  532. Filename: logPath,
  533. FileRotationConfig: log.FileRotationConfig{
  534. Rotate: sec.Key("LOG_ROTATE").MustBool(true),
  535. Daily: sec.Key("DAILY_ROTATE").MustBool(true),
  536. MaxSize: 1 << uint(sec.Key("MAX_SIZE_SHIFT").MustInt(28)),
  537. MaxLines: sec.Key("MAX_LINES").MustInt64(1000000),
  538. MaxDays: sec.Key("MAX_DAYS").MustInt64(7),
  539. },
  540. },
  541. }
  542. err = log.NewFile(c.Buffer, c.Config)
  543. case log.DefaultSlackName:
  544. c = &config{
  545. Buffer: buffer,
  546. Config: log.SlackConfig{
  547. Level: level,
  548. URL: sec.Key("URL").String(),
  549. },
  550. }
  551. err = log.NewSlack(c.Buffer, c.Config)
  552. case log.DefaultDiscordName:
  553. c = &config{
  554. Buffer: buffer,
  555. Config: log.DiscordConfig{
  556. Level: level,
  557. URL: sec.Key("URL").String(),
  558. Username: sec.Key("USERNAME").String(),
  559. },
  560. }
  561. default:
  562. continue
  563. }
  564. if err != nil {
  565. log.Fatal("Failed to init %s logger: %v", mode, err)
  566. return
  567. }
  568. LogConfigs[i] = c
  569. log.Trace("Log mode: %s (%s)", strings.Title(mode), strings.Title(strings.ToLower(level.String())))
  570. }
  571. if !hasConsole {
  572. log.Remove(log.DefaultConsoleName)
  573. }
  574. }
  575. var Service struct {
  576. ActiveCodeLives int
  577. ResetPwdCodeLives int
  578. RegisterEmailConfirm bool
  579. DisableRegistration bool
  580. ShowRegistrationButton bool
  581. RequireSignInView bool
  582. EnableNotifyMail bool
  583. EnableReverseProxyAuth bool
  584. EnableReverseProxyAutoRegister bool
  585. EnableCaptcha bool
  586. }
  587. func newService() {
  588. sec := File.Section("service")
  589. Service.ActiveCodeLives = sec.Key("ACTIVE_CODE_LIVE_MINUTES").MustInt(180)
  590. Service.ResetPwdCodeLives = sec.Key("RESET_PASSWD_CODE_LIVE_MINUTES").MustInt(180)
  591. Service.DisableRegistration = sec.Key("DISABLE_REGISTRATION").MustBool()
  592. Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!Service.DisableRegistration)
  593. Service.RequireSignInView = sec.Key("REQUIRE_SIGNIN_VIEW").MustBool()
  594. Service.EnableReverseProxyAuth = sec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION").MustBool()
  595. Service.EnableReverseProxyAutoRegister = sec.Key("ENABLE_REVERSE_PROXY_AUTO_REGISTRATION").MustBool()
  596. Service.EnableCaptcha = sec.Key("ENABLE_CAPTCHA").MustBool()
  597. }
  598. func newCacheService() {
  599. CacheAdapter = File.Section("cache").Key("ADAPTER").In("memory", []string{"memory", "redis", "memcache"})
  600. switch CacheAdapter {
  601. case "memory":
  602. CacheInterval = File.Section("cache").Key("INTERVAL").MustInt(60)
  603. case "redis", "memcache":
  604. CacheConn = strings.Trim(File.Section("cache").Key("HOST").String(), "\" ")
  605. default:
  606. log.Fatal("Unrecognized cache adapter %q", CacheAdapter)
  607. return
  608. }
  609. log.Trace("Cache service is enabled")
  610. }
  611. func newSessionService() {
  612. SessionConfig.Provider = File.Section("session").Key("PROVIDER").In("memory",
  613. []string{"memory", "file", "redis", "mysql"})
  614. SessionConfig.ProviderConfig = strings.Trim(File.Section("session").Key("PROVIDER_CONFIG").String(), "\" ")
  615. SessionConfig.CookieName = File.Section("session").Key("COOKIE_NAME").MustString("i_like_gogs")
  616. SessionConfig.CookiePath = Server.Subpath
  617. SessionConfig.Secure = File.Section("session").Key("COOKIE_SECURE").MustBool()
  618. SessionConfig.Gclifetime = File.Section("session").Key("GC_INTERVAL_TIME").MustInt64(3600)
  619. SessionConfig.Maxlifetime = File.Section("session").Key("SESSION_LIFE_TIME").MustInt64(86400)
  620. CSRFCookieName = File.Section("session").Key("CSRF_COOKIE_NAME").MustString("_csrf")
  621. log.Trace("Session service is enabled")
  622. }
  623. func newRegisterMailService() {
  624. if !File.Section("service").Key("REGISTER_EMAIL_CONFIRM").MustBool() {
  625. return
  626. } else if !Email.Enabled {
  627. log.Warn("Email confirmation is not enabled due to the mail service is not available")
  628. return
  629. }
  630. Service.RegisterEmailConfirm = true
  631. log.Trace("Email confirmation is enabled")
  632. }
  633. // newNotifyMailService initializes notification email service options from configuration.
  634. // No non-error log will be printed in hook mode.
  635. func newNotifyMailService() {
  636. if !File.Section("service").Key("ENABLE_NOTIFY_MAIL").MustBool() {
  637. return
  638. } else if !Email.Enabled {
  639. log.Warn("Email notification is not enabled due to the mail service is not available")
  640. return
  641. }
  642. Service.EnableNotifyMail = true
  643. if HookMode {
  644. return
  645. }
  646. log.Trace("Email notification is enabled")
  647. }
  648. func NewService() {
  649. newService()
  650. }
  651. func NewServices() {
  652. newService()
  653. newCacheService()
  654. newSessionService()
  655. newRegisterMailService()
  656. newNotifyMailService()
  657. }
  658. // HookMode indicates whether program starts as Git server-side hook callback.
  659. var HookMode bool
  660. // NewPostReceiveHookServices initializes all services that are needed by
  661. // Git server-side post-receive hook callback.
  662. func NewPostReceiveHookServices() {
  663. HookMode = true
  664. newService()
  665. newNotifyMailService()
  666. }