Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

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