setting.go 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875
  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 setting
  5. import (
  6. "net/mail"
  7. "net/url"
  8. "os"
  9. "os/exec"
  10. "path"
  11. "path/filepath"
  12. "runtime"
  13. "strconv"
  14. "strings"
  15. "time"
  16. "github.com/Unknwon/com"
  17. _ "github.com/go-macaron/cache/memcache"
  18. _ "github.com/go-macaron/cache/redis"
  19. "github.com/go-macaron/session"
  20. _ "github.com/go-macaron/session/redis"
  21. log "gopkg.in/clog.v1"
  22. "gopkg.in/ini.v1"
  23. "github.com/gogits/go-libravatar"
  24. "github.com/gogits/gogs/pkg/bindata"
  25. "github.com/gogits/gogs/pkg/user"
  26. )
  27. type Scheme string
  28. const (
  29. SCHEME_HTTP Scheme = "http"
  30. SCHEME_HTTPS Scheme = "https"
  31. SCHEME_FCGI Scheme = "fcgi"
  32. SCHEME_UNIX_SOCKET Scheme = "unix"
  33. )
  34. type LandingPage string
  35. const (
  36. LANDING_PAGE_HOME LandingPage = "/"
  37. LANDING_PAGE_EXPLORE LandingPage = "/explore"
  38. )
  39. var (
  40. // Build information should only be set by -ldflags.
  41. BuildTime string
  42. BuildGitHash string
  43. // App settings
  44. AppVer string
  45. AppName string
  46. AppURL string
  47. AppSubURL string
  48. AppSubURLDepth int // Number of slashes
  49. AppPath string
  50. AppDataPath string
  51. // Server settings
  52. Protocol Scheme
  53. Domain string
  54. HTTPAddr string
  55. HTTPPort string
  56. LocalURL string
  57. OfflineMode bool
  58. DisableRouterLog bool
  59. CertFile, KeyFile string
  60. TLSMinVersion string
  61. StaticRootPath string
  62. EnableGzip bool
  63. LandingPageURL LandingPage
  64. UnixSocketPermission uint32
  65. HTTP struct {
  66. AccessControlAllowOrigin string
  67. }
  68. SSH struct {
  69. Disabled bool `ini:"DISABLE_SSH"`
  70. StartBuiltinServer bool `ini:"START_SSH_SERVER"`
  71. Domain string `ini:"SSH_DOMAIN"`
  72. Port int `ini:"SSH_PORT"`
  73. ListenHost string `ini:"SSH_LISTEN_HOST"`
  74. ListenPort int `ini:"SSH_LISTEN_PORT"`
  75. RootPath string `ini:"SSH_ROOT_PATH"`
  76. ServerCiphers []string `ini:"SSH_SERVER_CIPHERS"`
  77. KeyTestPath string `ini:"SSH_KEY_TEST_PATH"`
  78. KeygenPath string `ini:"SSH_KEYGEN_PATH"`
  79. MinimumKeySizeCheck bool `ini:"-"`
  80. MinimumKeySizes map[string]int `ini:"-"`
  81. }
  82. // Security settings
  83. InstallLock bool
  84. SecretKey string
  85. LoginRememberDays int
  86. CookieUserName string
  87. CookieRememberName string
  88. CookieSecure bool
  89. ReverseProxyAuthUser string
  90. EnableLoginStatusCookie bool
  91. LoginStatusCookieName string
  92. // Database settings
  93. UseSQLite3 bool
  94. UseMySQL bool
  95. UsePostgreSQL bool
  96. UseMSSQL bool
  97. // Repository settings
  98. Repository struct {
  99. AnsiCharset string
  100. ForcePrivate bool
  101. MaxCreationLimit int
  102. MirrorQueueLength int
  103. PullRequestQueueLength int
  104. PreferredLicenses []string
  105. DisableHTTPGit bool `ini:"DISABLE_HTTP_GIT"`
  106. EnableLocalPathMigration bool
  107. CommitsFetchConcurrency int
  108. EnableRawFileRenderMode bool
  109. // Repository editor settings
  110. Editor struct {
  111. LineWrapExtensions []string
  112. PreviewableFileModes []string
  113. } `ini:"-"`
  114. // Repository upload settings
  115. Upload struct {
  116. Enabled bool
  117. TempPath string
  118. AllowedTypes []string `delim:"|"`
  119. FileMaxSize int64
  120. MaxFiles int
  121. } `ini:"-"`
  122. }
  123. RepoRootPath string
  124. ScriptType string
  125. // Webhook settings
  126. Webhook struct {
  127. Types []string
  128. QueueLength int
  129. DeliverTimeout int
  130. SkipTLSVerify bool `ini:"SKIP_TLS_VERIFY"`
  131. PagingNum int
  132. }
  133. // Release settigns
  134. Release struct {
  135. Attachment struct {
  136. Enabled bool
  137. TempPath string
  138. AllowedTypes []string `delim:"|"`
  139. MaxSize int64
  140. MaxFiles int
  141. } `ini:"-"`
  142. }
  143. // Markdown sttings
  144. Markdown struct {
  145. EnableHardLineBreak bool
  146. CustomURLSchemes []string `ini:"CUSTOM_URL_SCHEMES"`
  147. FileExtensions []string
  148. }
  149. // Smartypants settings
  150. Smartypants struct {
  151. Enabled bool
  152. Fractions bool
  153. Dashes bool
  154. LatexDashes bool
  155. AngledQuotes bool
  156. }
  157. // Admin settings
  158. Admin struct {
  159. DisableRegularOrgCreation bool
  160. }
  161. // Picture settings
  162. AvatarUploadPath string
  163. GravatarSource string
  164. DisableGravatar bool
  165. EnableFederatedAvatar bool
  166. LibravatarService *libravatar.Libravatar
  167. // Log settings
  168. LogRootPath string
  169. LogModes []string
  170. LogConfigs []interface{}
  171. // Attachment settings
  172. AttachmentPath string
  173. AttachmentAllowedTypes string
  174. AttachmentMaxSize int64
  175. AttachmentMaxFiles int
  176. AttachmentEnabled bool
  177. // Time settings
  178. TimeFormat string
  179. // Cache settings
  180. CacheAdapter string
  181. CacheInterval int
  182. CacheConn string
  183. // Session settings
  184. SessionConfig session.Options
  185. CSRFCookieName string
  186. // Cron tasks
  187. Cron struct {
  188. UpdateMirror struct {
  189. Enabled bool
  190. RunAtStart bool
  191. Schedule string
  192. } `ini:"cron.update_mirrors"`
  193. RepoHealthCheck struct {
  194. Enabled bool
  195. RunAtStart bool
  196. Schedule string
  197. Timeout time.Duration
  198. Args []string `delim:" "`
  199. } `ini:"cron.repo_health_check"`
  200. CheckRepoStats struct {
  201. Enabled bool
  202. RunAtStart bool
  203. Schedule string
  204. } `ini:"cron.check_repo_stats"`
  205. RepoArchiveCleanup struct {
  206. Enabled bool
  207. RunAtStart bool
  208. Schedule string
  209. OlderThan time.Duration
  210. } `ini:"cron.repo_archive_cleanup"`
  211. }
  212. // Git settings
  213. Git struct {
  214. Version string `ini:"-"`
  215. DisableDiffHighlight bool
  216. MaxGitDiffLines int
  217. MaxGitDiffLineCharacters int
  218. MaxGitDiffFiles int
  219. GCArgs []string `delim:" "`
  220. Timeout struct {
  221. Migrate int
  222. Mirror int
  223. Clone int
  224. Pull int
  225. GC int `ini:"GC"`
  226. } `ini:"git.timeout"`
  227. }
  228. // Mirror settings
  229. Mirror struct {
  230. DefaultInterval int
  231. }
  232. // API settings
  233. API struct {
  234. MaxResponseItems int
  235. }
  236. // UI settings
  237. UI struct {
  238. ExplorePagingNum int
  239. IssuePagingNum int
  240. FeedMaxCommitNum int
  241. ThemeColorMetaTag string
  242. MaxDisplayFileSize int64
  243. Admin struct {
  244. UserPagingNum int
  245. RepoPagingNum int
  246. NoticePagingNum int
  247. OrgPagingNum int
  248. } `ini:"ui.admin"`
  249. User struct {
  250. RepoPagingNum int
  251. NewsFeedPagingNum int
  252. CommitsPagingNum int
  253. } `ini:"ui.user"`
  254. }
  255. // I18n settings
  256. Langs []string
  257. Names []string
  258. dateLangs map[string]string
  259. // Highlight settings are loaded in modules/template/hightlight.go
  260. // Other settings
  261. ShowFooterBranding bool
  262. ShowFooterVersion bool
  263. ShowFooterTemplateLoadTime bool
  264. SupportMiniWinService bool
  265. // Global setting objects
  266. Cfg *ini.File
  267. CustomPath string // Custom directory path
  268. CustomConf string
  269. ProdMode bool
  270. RunUser string
  271. IsWindows bool
  272. HasRobotsTxt bool
  273. )
  274. // DateLang transforms standard language locale name to corresponding value in datetime plugin.
  275. func DateLang(lang string) string {
  276. name, ok := dateLangs[lang]
  277. if ok {
  278. return name
  279. }
  280. return "en"
  281. }
  282. // execPath returns the executable path.
  283. func execPath() (string, error) {
  284. file, err := exec.LookPath(os.Args[0])
  285. if err != nil {
  286. return "", err
  287. }
  288. return filepath.Abs(file)
  289. }
  290. func init() {
  291. IsWindows = runtime.GOOS == "windows"
  292. log.New(log.CONSOLE, log.ConsoleConfig{})
  293. var err error
  294. if AppPath, err = execPath(); err != nil {
  295. log.Fatal(2, "Fail to get app path: %v\n", err)
  296. }
  297. // Note: we don't use path.Dir here because it does not handle case
  298. // which path starts with two "/" in Windows: "//psf/Home/..."
  299. AppPath = strings.Replace(AppPath, "\\", "/", -1)
  300. }
  301. // WorkDir returns absolute path of work directory.
  302. func WorkDir() (string, error) {
  303. wd := os.Getenv("GOGS_WORK_DIR")
  304. if len(wd) > 0 {
  305. return wd, nil
  306. }
  307. i := strings.LastIndex(AppPath, "/")
  308. if i == -1 {
  309. return AppPath, nil
  310. }
  311. return AppPath[:i], nil
  312. }
  313. func forcePathSeparator(path string) {
  314. if strings.Contains(path, "\\") {
  315. log.Fatal(2, "Do not use '\\' or '\\\\' in paths, instead, please use '/' in all places")
  316. }
  317. }
  318. // IsRunUserMatchCurrentUser returns false if configured run user does not match
  319. // actual user that runs the app. The first return value is the actual user name.
  320. // This check is ignored under Windows since SSH remote login is not the main
  321. // method to login on Windows.
  322. func IsRunUserMatchCurrentUser(runUser string) (string, bool) {
  323. if IsWindows {
  324. return "", true
  325. }
  326. currentUser := user.CurrentUsername()
  327. return currentUser, runUser == currentUser
  328. }
  329. // NewContext initializes configuration context.
  330. // NOTE: do not print any log except error.
  331. func NewContext() {
  332. workDir, err := WorkDir()
  333. if err != nil {
  334. log.Fatal(2, "Fail to get work directory: %v", err)
  335. }
  336. Cfg, err = ini.Load(bindata.MustAsset("conf/app.ini"))
  337. if err != nil {
  338. log.Fatal(2, "Fail to parse 'conf/app.ini': %v", err)
  339. }
  340. CustomPath = os.Getenv("GOGS_CUSTOM")
  341. if len(CustomPath) == 0 {
  342. CustomPath = workDir + "/custom"
  343. }
  344. if len(CustomConf) == 0 {
  345. CustomConf = CustomPath + "/conf/app.ini"
  346. }
  347. if com.IsFile(CustomConf) {
  348. if err = Cfg.Append(CustomConf); err != nil {
  349. log.Fatal(2, "Fail to load custom conf '%s': %v", CustomConf, err)
  350. }
  351. } else {
  352. log.Warn("Custom config '%s' not found, ignore this if you're running first time", CustomConf)
  353. }
  354. Cfg.NameMapper = ini.AllCapsUnderscore
  355. homeDir, err := com.HomeDir()
  356. if err != nil {
  357. log.Fatal(2, "Fail to get home directory: %v", err)
  358. }
  359. homeDir = strings.Replace(homeDir, "\\", "/", -1)
  360. LogRootPath = Cfg.Section("log").Key("ROOT_PATH").MustString(path.Join(workDir, "log"))
  361. forcePathSeparator(LogRootPath)
  362. sec := Cfg.Section("server")
  363. AppName = Cfg.Section("").Key("APP_NAME").MustString("Gogs")
  364. AppURL = sec.Key("ROOT_URL").MustString("http://localhost:3000/")
  365. if AppURL[len(AppURL)-1] != '/' {
  366. AppURL += "/"
  367. }
  368. // Check if has app suburl.
  369. url, err := url.Parse(AppURL)
  370. if err != nil {
  371. log.Fatal(2, "Invalid ROOT_URL '%s': %s", AppURL, err)
  372. }
  373. // Suburl should start with '/' and end without '/', such as '/{subpath}'.
  374. // This value is empty if site does not have sub-url.
  375. AppSubURL = strings.TrimSuffix(url.Path, "/")
  376. AppSubURLDepth = strings.Count(AppSubURL, "/")
  377. Protocol = SCHEME_HTTP
  378. if sec.Key("PROTOCOL").String() == "https" {
  379. Protocol = SCHEME_HTTPS
  380. CertFile = sec.Key("CERT_FILE").String()
  381. KeyFile = sec.Key("KEY_FILE").String()
  382. TLSMinVersion = sec.Key("TLS_MIN_VERSION").String()
  383. } else if sec.Key("PROTOCOL").String() == "fcgi" {
  384. Protocol = SCHEME_FCGI
  385. } else if sec.Key("PROTOCOL").String() == "unix" {
  386. Protocol = SCHEME_UNIX_SOCKET
  387. UnixSocketPermissionRaw := sec.Key("UNIX_SOCKET_PERMISSION").MustString("666")
  388. UnixSocketPermissionParsed, err := strconv.ParseUint(UnixSocketPermissionRaw, 8, 32)
  389. if err != nil || UnixSocketPermissionParsed > 0777 {
  390. log.Fatal(2, "Fail to parse unixSocketPermission: %s", UnixSocketPermissionRaw)
  391. }
  392. UnixSocketPermission = uint32(UnixSocketPermissionParsed)
  393. }
  394. Domain = sec.Key("DOMAIN").MustString("localhost")
  395. HTTPAddr = sec.Key("HTTP_ADDR").MustString("0.0.0.0")
  396. HTTPPort = sec.Key("HTTP_PORT").MustString("3000")
  397. LocalURL = sec.Key("LOCAL_ROOT_URL").MustString(string(Protocol) + "://localhost:" + HTTPPort + "/")
  398. OfflineMode = sec.Key("OFFLINE_MODE").MustBool()
  399. DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool()
  400. StaticRootPath = sec.Key("STATIC_ROOT_PATH").MustString(workDir)
  401. AppDataPath = sec.Key("APP_DATA_PATH").MustString("data")
  402. EnableGzip = sec.Key("ENABLE_GZIP").MustBool()
  403. switch sec.Key("LANDING_PAGE").MustString("home") {
  404. case "explore":
  405. LandingPageURL = LANDING_PAGE_EXPLORE
  406. default:
  407. LandingPageURL = LANDING_PAGE_HOME
  408. }
  409. SSH.RootPath = path.Join(homeDir, ".ssh")
  410. SSH.ServerCiphers = sec.Key("SSH_SERVER_CIPHERS").Strings(",")
  411. SSH.KeyTestPath = os.TempDir()
  412. if err = Cfg.Section("server").MapTo(&SSH); err != nil {
  413. log.Fatal(2, "Fail to map SSH settings: %v", err)
  414. }
  415. // When disable SSH, start builtin server value is ignored.
  416. if SSH.Disabled {
  417. SSH.StartBuiltinServer = false
  418. }
  419. if !SSH.Disabled && !SSH.StartBuiltinServer {
  420. if err := os.MkdirAll(SSH.RootPath, 0700); err != nil {
  421. log.Fatal(2, "Fail to create '%s': %v", SSH.RootPath, err)
  422. } else if err = os.MkdirAll(SSH.KeyTestPath, 0644); err != nil {
  423. log.Fatal(2, "Fail to create '%s': %v", SSH.KeyTestPath, err)
  424. }
  425. }
  426. SSH.MinimumKeySizeCheck = sec.Key("MINIMUM_KEY_SIZE_CHECK").MustBool()
  427. SSH.MinimumKeySizes = map[string]int{}
  428. minimumKeySizes := Cfg.Section("ssh.minimum_key_sizes").Keys()
  429. for _, key := range minimumKeySizes {
  430. if key.MustInt() != -1 {
  431. SSH.MinimumKeySizes[strings.ToLower(key.Name())] = key.MustInt()
  432. }
  433. }
  434. sec = Cfg.Section("security")
  435. InstallLock = sec.Key("INSTALL_LOCK").MustBool()
  436. SecretKey = sec.Key("SECRET_KEY").String()
  437. LoginRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt()
  438. CookieUserName = sec.Key("COOKIE_USERNAME").String()
  439. CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").String()
  440. CookieSecure = sec.Key("COOKIE_SECURE").MustBool(false)
  441. ReverseProxyAuthUser = sec.Key("REVERSE_PROXY_AUTHENTICATION_USER").MustString("X-WEBAUTH-USER")
  442. EnableLoginStatusCookie = sec.Key("ENABLE_LOGIN_STATUS_COOKIE").MustBool(false)
  443. LoginStatusCookieName = sec.Key("LOGIN_STATUS_COOKIE_NAME").MustString("login_status")
  444. sec = Cfg.Section("attachment")
  445. AttachmentPath = sec.Key("PATH").MustString(path.Join(AppDataPath, "attachments"))
  446. if !filepath.IsAbs(AttachmentPath) {
  447. AttachmentPath = path.Join(workDir, AttachmentPath)
  448. }
  449. AttachmentAllowedTypes = strings.Replace(sec.Key("ALLOWED_TYPES").MustString("image/jpeg,image/png"), "|", ",", -1)
  450. AttachmentMaxSize = sec.Key("MAX_SIZE").MustInt64(4)
  451. AttachmentMaxFiles = sec.Key("MAX_FILES").MustInt(5)
  452. AttachmentEnabled = sec.Key("ENABLED").MustBool(true)
  453. TimeFormat = map[string]string{
  454. "ANSIC": time.ANSIC,
  455. "UnixDate": time.UnixDate,
  456. "RubyDate": time.RubyDate,
  457. "RFC822": time.RFC822,
  458. "RFC822Z": time.RFC822Z,
  459. "RFC850": time.RFC850,
  460. "RFC1123": time.RFC1123,
  461. "RFC1123Z": time.RFC1123Z,
  462. "RFC3339": time.RFC3339,
  463. "RFC3339Nano": time.RFC3339Nano,
  464. "Kitchen": time.Kitchen,
  465. "Stamp": time.Stamp,
  466. "StampMilli": time.StampMilli,
  467. "StampMicro": time.StampMicro,
  468. "StampNano": time.StampNano,
  469. }[Cfg.Section("time").Key("FORMAT").MustString("RFC1123")]
  470. RunUser = Cfg.Section("").Key("RUN_USER").String()
  471. // Does not check run user when the install lock is off.
  472. if InstallLock {
  473. currentUser, match := IsRunUserMatchCurrentUser(RunUser)
  474. if !match {
  475. log.Fatal(2, "Expect user '%s' but current user is: %s", RunUser, currentUser)
  476. }
  477. }
  478. ProdMode = Cfg.Section("").Key("RUN_MODE").String() == "prod"
  479. // Determine and create root git repository path.
  480. sec = Cfg.Section("repository")
  481. RepoRootPath = sec.Key("ROOT").MustString(path.Join(homeDir, "gogs-repositories"))
  482. forcePathSeparator(RepoRootPath)
  483. if !filepath.IsAbs(RepoRootPath) {
  484. RepoRootPath = path.Join(workDir, RepoRootPath)
  485. } else {
  486. RepoRootPath = path.Clean(RepoRootPath)
  487. }
  488. ScriptType = sec.Key("SCRIPT_TYPE").MustString("bash")
  489. if err = Cfg.Section("repository").MapTo(&Repository); err != nil {
  490. log.Fatal(2, "Fail to map Repository settings: %v", err)
  491. } else if err = Cfg.Section("repository.editor").MapTo(&Repository.Editor); err != nil {
  492. log.Fatal(2, "Fail to map Repository.Editor settings: %v", err)
  493. } else if err = Cfg.Section("repository.upload").MapTo(&Repository.Upload); err != nil {
  494. log.Fatal(2, "Fail to map Repository.Upload settings: %v", err)
  495. }
  496. if !filepath.IsAbs(Repository.Upload.TempPath) {
  497. Repository.Upload.TempPath = path.Join(workDir, Repository.Upload.TempPath)
  498. }
  499. sec = Cfg.Section("picture")
  500. AvatarUploadPath = sec.Key("AVATAR_UPLOAD_PATH").MustString(path.Join(AppDataPath, "avatars"))
  501. forcePathSeparator(AvatarUploadPath)
  502. if !filepath.IsAbs(AvatarUploadPath) {
  503. AvatarUploadPath = path.Join(workDir, AvatarUploadPath)
  504. }
  505. switch source := sec.Key("GRAVATAR_SOURCE").MustString("gravatar"); source {
  506. case "duoshuo":
  507. GravatarSource = "http://gravatar.duoshuo.com/avatar/"
  508. case "gravatar":
  509. GravatarSource = "https://secure.gravatar.com/avatar/"
  510. case "libravatar":
  511. GravatarSource = "https://seccdn.libravatar.org/avatar/"
  512. default:
  513. GravatarSource = source
  514. }
  515. DisableGravatar = sec.Key("DISABLE_GRAVATAR").MustBool()
  516. EnableFederatedAvatar = sec.Key("ENABLE_FEDERATED_AVATAR").MustBool(true)
  517. if OfflineMode {
  518. DisableGravatar = true
  519. EnableFederatedAvatar = false
  520. }
  521. if DisableGravatar {
  522. EnableFederatedAvatar = false
  523. }
  524. if EnableFederatedAvatar {
  525. LibravatarService = libravatar.New()
  526. parts := strings.Split(GravatarSource, "/")
  527. if len(parts) >= 3 {
  528. if parts[0] == "https:" {
  529. LibravatarService.SetUseHTTPS(true)
  530. LibravatarService.SetSecureFallbackHost(parts[2])
  531. } else {
  532. LibravatarService.SetUseHTTPS(false)
  533. LibravatarService.SetFallbackHost(parts[2])
  534. }
  535. }
  536. }
  537. if err = Cfg.Section("http").MapTo(&HTTP); err != nil {
  538. log.Fatal(2, "Fail to map HTTP settings: %v", err)
  539. } else if err = Cfg.Section("webhook").MapTo(&Webhook); err != nil {
  540. log.Fatal(2, "Fail to map Webhook settings: %v", err)
  541. } else if err = Cfg.Section("release.attachment").MapTo(&Release.Attachment); err != nil {
  542. log.Fatal(2, "Fail to map Release.Attachment settings: %v", err)
  543. } else if err = Cfg.Section("markdown").MapTo(&Markdown); err != nil {
  544. log.Fatal(2, "Fail to map Markdown settings: %v", err)
  545. } else if err = Cfg.Section("smartypants").MapTo(&Smartypants); err != nil {
  546. log.Fatal(2, "Fail to map Smartypants settings: %v", err)
  547. } else if err = Cfg.Section("admin").MapTo(&Admin); err != nil {
  548. log.Fatal(2, "Fail to map Admin settings: %v", err)
  549. } else if err = Cfg.Section("cron").MapTo(&Cron); err != nil {
  550. log.Fatal(2, "Fail to map Cron settings: %v", err)
  551. } else if err = Cfg.Section("git").MapTo(&Git); err != nil {
  552. log.Fatal(2, "Fail to map Git settings: %v", err)
  553. } else if err = Cfg.Section("mirror").MapTo(&Mirror); err != nil {
  554. log.Fatal(2, "Fail to map Mirror settings: %v", err)
  555. } else if err = Cfg.Section("api").MapTo(&API); err != nil {
  556. log.Fatal(2, "Fail to map API settings: %v", err)
  557. } else if err = Cfg.Section("ui").MapTo(&UI); err != nil {
  558. log.Fatal(2, "Fail to map UI settings: %v", err)
  559. }
  560. if Mirror.DefaultInterval <= 0 {
  561. Mirror.DefaultInterval = 24
  562. }
  563. Langs = Cfg.Section("i18n").Key("LANGS").Strings(",")
  564. Names = Cfg.Section("i18n").Key("NAMES").Strings(",")
  565. dateLangs = Cfg.Section("i18n.datelang").KeysHash()
  566. ShowFooterBranding = Cfg.Section("other").Key("SHOW_FOOTER_BRANDING").MustBool()
  567. ShowFooterVersion = Cfg.Section("other").Key("SHOW_FOOTER_VERSION").MustBool()
  568. ShowFooterTemplateLoadTime = Cfg.Section("other").Key("SHOW_FOOTER_TEMPLATE_LOAD_TIME").MustBool()
  569. HasRobotsTxt = com.IsFile(path.Join(CustomPath, "robots.txt"))
  570. }
  571. var Service struct {
  572. ActiveCodeLives int
  573. ResetPwdCodeLives int
  574. RegisterEmailConfirm bool
  575. DisableRegistration bool
  576. ShowRegistrationButton bool
  577. RequireSignInView bool
  578. EnableNotifyMail bool
  579. EnableReverseProxyAuth bool
  580. EnableReverseProxyAutoRegister bool
  581. EnableCaptcha bool
  582. }
  583. func newService() {
  584. sec := Cfg.Section("service")
  585. Service.ActiveCodeLives = sec.Key("ACTIVE_CODE_LIVE_MINUTES").MustInt(180)
  586. Service.ResetPwdCodeLives = sec.Key("RESET_PASSWD_CODE_LIVE_MINUTES").MustInt(180)
  587. Service.DisableRegistration = sec.Key("DISABLE_REGISTRATION").MustBool()
  588. Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!Service.DisableRegistration)
  589. Service.RequireSignInView = sec.Key("REQUIRE_SIGNIN_VIEW").MustBool()
  590. Service.EnableReverseProxyAuth = sec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION").MustBool()
  591. Service.EnableReverseProxyAutoRegister = sec.Key("ENABLE_REVERSE_PROXY_AUTO_REGISTRATION").MustBool()
  592. Service.EnableCaptcha = sec.Key("ENABLE_CAPTCHA").MustBool()
  593. }
  594. func newLogService() {
  595. if len(BuildTime) > 0 {
  596. log.Trace("Build Time: %s", BuildTime)
  597. log.Trace("Build Git Hash: %s", BuildGitHash)
  598. }
  599. // Because we always create a console logger as primary logger before all settings are loaded,
  600. // thus if user doesn't set console logger, we should remove it after other loggers are created.
  601. hasConsole := false
  602. // Get and check log modes.
  603. LogModes = strings.Split(Cfg.Section("log").Key("MODE").MustString("console"), ",")
  604. LogConfigs = make([]interface{}, len(LogModes))
  605. levelNames := map[string]log.LEVEL{
  606. "trace": log.TRACE,
  607. "info": log.INFO,
  608. "warn": log.WARN,
  609. "error": log.ERROR,
  610. "fatal": log.FATAL,
  611. }
  612. for i, mode := range LogModes {
  613. mode = strings.ToLower(strings.TrimSpace(mode))
  614. sec, err := Cfg.GetSection("log." + mode)
  615. if err != nil {
  616. log.Fatal(2, "Unknown logger mode: %s", mode)
  617. }
  618. validLevels := []string{"trace", "info", "warn", "error", "fatal"}
  619. name := Cfg.Section("log." + mode).Key("LEVEL").Validate(func(v string) string {
  620. v = strings.ToLower(v)
  621. if com.IsSliceContainsStr(validLevels, v) {
  622. return v
  623. }
  624. return "trace"
  625. })
  626. level := levelNames[name]
  627. // Generate log configuration.
  628. switch log.MODE(mode) {
  629. case log.CONSOLE:
  630. hasConsole = true
  631. LogConfigs[i] = log.ConsoleConfig{
  632. Level: level,
  633. BufferSize: Cfg.Section("log").Key("BUFFER_LEN").MustInt64(100),
  634. }
  635. case log.FILE:
  636. logPath := path.Join(LogRootPath, "gogs.log")
  637. if err = os.MkdirAll(path.Dir(logPath), os.ModePerm); err != nil {
  638. log.Fatal(2, "Fail to create log directory '%s': %v", path.Dir(logPath), err)
  639. }
  640. LogConfigs[i] = log.FileConfig{
  641. Level: level,
  642. BufferSize: Cfg.Section("log").Key("BUFFER_LEN").MustInt64(100),
  643. Filename: logPath,
  644. FileRotationConfig: log.FileRotationConfig{
  645. Rotate: sec.Key("LOG_ROTATE").MustBool(true),
  646. Daily: sec.Key("DAILY_ROTATE").MustBool(true),
  647. MaxSize: 1 << uint(sec.Key("MAX_SIZE_SHIFT").MustInt(28)),
  648. MaxLines: sec.Key("MAX_LINES").MustInt64(1000000),
  649. MaxDays: sec.Key("MAX_DAYS").MustInt64(7),
  650. },
  651. }
  652. case log.SLACK:
  653. LogConfigs[i] = log.SlackConfig{
  654. Level: level,
  655. BufferSize: Cfg.Section("log").Key("BUFFER_LEN").MustInt64(100),
  656. URL: sec.Key("URL").String(),
  657. }
  658. }
  659. log.New(log.MODE(mode), LogConfigs[i])
  660. log.Trace("Log Mode: %s (%s)", strings.Title(mode), strings.Title(name))
  661. }
  662. // Make sure everyone gets version info printed.
  663. log.Info("%s %s", AppName, AppVer)
  664. if !hasConsole {
  665. log.Delete(log.CONSOLE)
  666. }
  667. }
  668. func newCacheService() {
  669. CacheAdapter = Cfg.Section("cache").Key("ADAPTER").In("memory", []string{"memory", "redis", "memcache"})
  670. switch CacheAdapter {
  671. case "memory":
  672. CacheInterval = Cfg.Section("cache").Key("INTERVAL").MustInt(60)
  673. case "redis", "memcache":
  674. CacheConn = strings.Trim(Cfg.Section("cache").Key("HOST").String(), "\" ")
  675. default:
  676. log.Fatal(2, "Unknown cache adapter: %s", CacheAdapter)
  677. }
  678. log.Info("Cache Service Enabled")
  679. }
  680. func newSessionService() {
  681. SessionConfig.Provider = Cfg.Section("session").Key("PROVIDER").In("memory",
  682. []string{"memory", "file", "redis", "mysql"})
  683. SessionConfig.ProviderConfig = strings.Trim(Cfg.Section("session").Key("PROVIDER_CONFIG").String(), "\" ")
  684. SessionConfig.CookieName = Cfg.Section("session").Key("COOKIE_NAME").MustString("i_like_gogits")
  685. SessionConfig.CookiePath = AppSubURL
  686. SessionConfig.Secure = Cfg.Section("session").Key("COOKIE_SECURE").MustBool()
  687. SessionConfig.Gclifetime = Cfg.Section("session").Key("GC_INTERVAL_TIME").MustInt64(3600)
  688. SessionConfig.Maxlifetime = Cfg.Section("session").Key("SESSION_LIFE_TIME").MustInt64(86400)
  689. CSRFCookieName = Cfg.Section("session").Key("CSRF_COOKIE_NAME").MustString("_csrf")
  690. log.Info("Session Service Enabled")
  691. }
  692. // Mailer represents mail service.
  693. type Mailer struct {
  694. QueueLength int
  695. Subject string
  696. Host string
  697. From string
  698. FromEmail string
  699. User, Passwd string
  700. DisableHelo bool
  701. HeloHostname string
  702. SkipVerify bool
  703. UseCertificate bool
  704. CertFile, KeyFile string
  705. UsePlainText bool
  706. }
  707. var (
  708. MailService *Mailer
  709. )
  710. func newMailService() {
  711. sec := Cfg.Section("mailer")
  712. // Check mailer setting.
  713. if !sec.Key("ENABLED").MustBool() {
  714. return
  715. }
  716. MailService = &Mailer{
  717. QueueLength: sec.Key("SEND_BUFFER_LEN").MustInt(100),
  718. Subject: sec.Key("SUBJECT").MustString(AppName),
  719. Host: sec.Key("HOST").String(),
  720. User: sec.Key("USER").String(),
  721. Passwd: sec.Key("PASSWD").String(),
  722. DisableHelo: sec.Key("DISABLE_HELO").MustBool(),
  723. HeloHostname: sec.Key("HELO_HOSTNAME").String(),
  724. SkipVerify: sec.Key("SKIP_VERIFY").MustBool(),
  725. UseCertificate: sec.Key("USE_CERTIFICATE").MustBool(),
  726. CertFile: sec.Key("CERT_FILE").String(),
  727. KeyFile: sec.Key("KEY_FILE").String(),
  728. UsePlainText: sec.Key("USE_PLAIN_TEXT").MustBool(),
  729. }
  730. MailService.From = sec.Key("FROM").MustString(MailService.User)
  731. if len(MailService.From) > 0 {
  732. parsed, err := mail.ParseAddress(MailService.From)
  733. if err != nil {
  734. log.Fatal(2, "Invalid mailer.FROM (%s): %v", MailService.From, err)
  735. }
  736. MailService.FromEmail = parsed.Address
  737. }
  738. log.Info("Mail Service Enabled")
  739. }
  740. func newRegisterMailService() {
  741. if !Cfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").MustBool() {
  742. return
  743. } else if MailService == nil {
  744. log.Warn("Register Mail Service: Mail Service is not enabled")
  745. return
  746. }
  747. Service.RegisterEmailConfirm = true
  748. log.Info("Register Mail Service Enabled")
  749. }
  750. func newNotifyMailService() {
  751. if !Cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").MustBool() {
  752. return
  753. } else if MailService == nil {
  754. log.Warn("Notify Mail Service: Mail Service is not enabled")
  755. return
  756. }
  757. Service.EnableNotifyMail = true
  758. log.Info("Notify Mail Service Enabled")
  759. }
  760. func NewService() {
  761. newService()
  762. }
  763. func NewServices() {
  764. newService()
  765. newLogService()
  766. newCacheService()
  767. newSessionService()
  768. newMailService()
  769. newRegisterMailService()
  770. newNotifyMailService()
  771. }