webuiServer.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. package httpservers
  2. import (
  3. "encoding/json"
  4. // cors "github.com/OliveTin/OliveTin/internal/cors"
  5. log "github.com/sirupsen/logrus"
  6. "net/http"
  7. "os"
  8. "path"
  9. "path/filepath"
  10. config "github.com/OliveTin/OliveTin/internal/config"
  11. installationinfo "github.com/OliveTin/OliveTin/internal/installationinfo"
  12. sv "github.com/OliveTin/OliveTin/internal/stringvariables"
  13. )
  14. var (
  15. customThemeCss []byte
  16. customThemeCssRead = false
  17. )
  18. type webUISettings struct {
  19. Rest string
  20. ShowFooter bool
  21. ShowNavigation bool
  22. ShowNewVersions bool
  23. AvailableVersion string
  24. CurrentVersion string
  25. PageTitle string
  26. SectionNavigationStyle string
  27. DefaultIconForBack string
  28. SshFoundKey string
  29. SshFoundConfig string
  30. EnableCustomJs bool
  31. AuthLoginUrl string
  32. AuthLocalLogin bool
  33. AuthOAuth2Providers []publicOAuth2Provider
  34. AdditionalLinks []*config.NavigationLink
  35. }
  36. func findWebuiDir() string {
  37. directoriesToSearch := []string{
  38. cfg.WebUIDir,
  39. "../webui/",
  40. "/usr/share/OliveTin/webui/",
  41. "/var/www/OliveTin/",
  42. "/var/www/olivetin/",
  43. "/etc/OliveTin/webui/",
  44. }
  45. // Use a classic i := 0 style for loop here instead of range, as the
  46. // search order must be deterministic - the order that the slice was defined in.
  47. for i := 0; i < len(directoriesToSearch); i++ {
  48. dir := directoriesToSearch[i]
  49. absdir, _ := filepath.Abs(dir)
  50. if _, err := os.Stat(absdir); !os.IsNotExist(err) {
  51. log.WithFields(log.Fields{
  52. "dir": absdir,
  53. }).Infof("Found the webui directory")
  54. sv.Set("internal.webuidir", absdir+" ("+dir+")")
  55. return dir
  56. }
  57. }
  58. log.Warnf("Did not find the webui directory, you will probably get 404 errors.")
  59. return "./webui" // Should not exist
  60. }
  61. func findCustomWebuiDir() string {
  62. dir := path.Join(cfg.GetDir(), "custom-webui")
  63. return dir
  64. }
  65. func setupCustomWebuiDir() {
  66. dir := findCustomWebuiDir()
  67. err := os.MkdirAll(path.Join(dir, "themes/"), 0775)
  68. if err != nil {
  69. log.Warnf("Could not create themes directory: %v", err)
  70. sv.Set("internal.themesdir", err.Error())
  71. } else {
  72. sv.Set("internal.themesdir", dir)
  73. }
  74. }
  75. func generateThemeCss(w http.ResponseWriter, r *http.Request) {
  76. themeCssFilename := path.Join(findCustomWebuiDir(), "themes", cfg.ThemeName, "theme.css")
  77. if !customThemeCssRead || cfg.ThemeCacheDisabled {
  78. customThemeCssRead = true
  79. if _, err := os.Stat(themeCssFilename); err == nil {
  80. customThemeCss, err = os.ReadFile(themeCssFilename)
  81. } else {
  82. log.Debugf("Theme CSS not read: %v", err)
  83. customThemeCss = []byte("/* not found */")
  84. }
  85. }
  86. w.Header().Add("Content-Type", "text/css")
  87. w.Write(customThemeCss)
  88. }
  89. type publicOAuth2Provider struct {
  90. Name string
  91. Title string
  92. Icon string
  93. }
  94. func buildPublicOAuth2ProvidersList(cfg *config.Config) []publicOAuth2Provider {
  95. var publicProviders []publicOAuth2Provider
  96. for _, provider := range cfg.AuthOAuth2Providers {
  97. publicProviders = append(publicProviders, publicOAuth2Provider{
  98. Name: provider.Name,
  99. Title: provider.Title,
  100. Icon: provider.Icon,
  101. })
  102. }
  103. return publicProviders
  104. }
  105. func generateWebUISettings(w http.ResponseWriter, r *http.Request) {
  106. jsonRet, _ := json.Marshal(webUISettings{
  107. Rest: cfg.ExternalRestAddress + "/api/",
  108. ShowFooter: cfg.ShowFooter,
  109. ShowNavigation: cfg.ShowNavigation,
  110. ShowNewVersions: cfg.ShowNewVersions,
  111. AvailableVersion: installationinfo.Runtime.AvailableVersion,
  112. CurrentVersion: installationinfo.Build.Version,
  113. PageTitle: cfg.PageTitle,
  114. SectionNavigationStyle: cfg.SectionNavigationStyle,
  115. DefaultIconForBack: cfg.DefaultIconForBack,
  116. SshFoundKey: installationinfo.Runtime.SshFoundKey,
  117. SshFoundConfig: installationinfo.Runtime.SshFoundConfig,
  118. EnableCustomJs: cfg.EnableCustomJs,
  119. AuthLoginUrl: cfg.AuthLoginUrl,
  120. AuthLocalLogin: true,
  121. AuthOAuth2Providers: buildPublicOAuth2ProvidersList(cfg),
  122. AdditionalLinks: cfg.AdditionalNavigationLinks,
  123. })
  124. w.Header().Add("Content-Type", "application/json")
  125. _, err := w.Write([]byte(jsonRet))
  126. if err != nil {
  127. log.Warnf("Could not write webui settings: %v", err)
  128. }
  129. }
  130. func startWebUIServer(cfg *config.Config) {
  131. log.WithFields(log.Fields{
  132. "address": cfg.ListenAddressWebUI,
  133. }).Info("Starting WebUI server")
  134. setupCustomWebuiDir()
  135. mux := http.NewServeMux()
  136. mux.Handle("/custom-webui/", http.StripPrefix("/custom-webui/", http.FileServer(http.Dir(findCustomWebuiDir()))))
  137. mux.HandleFunc("/theme.css", generateThemeCss)
  138. mux.HandleFunc("/webUiSettings.json", generateWebUISettings)
  139. webuiDir := findWebuiDir()
  140. mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  141. dirName := path.Dir(r.URL.Path)
  142. // Mangle requests for any path like /logs or /config to load the webui index.html
  143. if path.Ext(r.URL.Path) == "" && r.URL.Path != "/" {
  144. log.Debugf("Mangling request for %s to /index.html", r.URL.Path)
  145. http.ServeFile(w, r, path.Join(webuiDir, "index.html"))
  146. } else {
  147. http.StripPrefix(dirName, http.FileServer(http.Dir(webuiDir))).ServeHTTP(w, r)
  148. }
  149. })
  150. srv := &http.Server{
  151. Addr: cfg.ListenAddressWebUI,
  152. Handler: mux,
  153. }
  154. log.Fatal(srv.ListenAndServe())
  155. }