Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

setting.go 36KB

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