webuiServer.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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. "github.com/jamesread/golure/pkg/dirs"
  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. type webUIServer struct {
  15. cfg *config.Config
  16. webuiDir string
  17. }
  18. var (
  19. customThemeCss []byte
  20. customThemeCssRead = false
  21. )
  22. type webUISettings struct {
  23. Rest string
  24. ShowFooter bool
  25. ShowNavigation bool
  26. ShowNewVersions bool
  27. AvailableVersion string
  28. CurrentVersion string
  29. PageTitle string
  30. SectionNavigationStyle string
  31. DefaultIconForBack string
  32. EnableCustomJs bool
  33. AuthLoginUrl string
  34. AuthLocalLogin bool
  35. StyleMods []string
  36. AuthOAuth2Providers []publicOAuth2Provider
  37. AdditionalLinks []*config.NavigationLink
  38. }
  39. func NewWebUIServer(cfg *config.Config) *webUIServer {
  40. s := &webUIServer{
  41. cfg: cfg,
  42. }
  43. s.webuiDir = s.findWebuiDir()
  44. s.setupCustomWebuiDir()
  45. return s
  46. }
  47. func (s *webUIServer) handleWebui(w http.ResponseWriter, r *http.Request) {
  48. //dirName := path.Dir(r.URL.Path)
  49. // Mangle requests for any path like /logs or /config to load the webui index.html
  50. if path.Ext(r.URL.Path) == "" && r.URL.Path != "/" {
  51. log.Debugf("Mangling request for %s to /index.html", r.URL.Path)
  52. http.ServeFile(w, r, path.Join(s.webuiDir, "index.html"))
  53. } else {
  54. log.Infof("Serving webui from %s for %s", s.webuiDir, r.URL.Path)
  55. http.ServeFile(w, r, path.Join(s.webuiDir, r.URL.Path))
  56. // http.StripPrefix(dirName, http.FileServer(http.Dir(s.webuiDir))).ServeHTTP(w, r)
  57. }
  58. }
  59. func (s *webUIServer) findWebuiDir() string {
  60. directoriesToSearch := []string{
  61. s.cfg.WebUIDir,
  62. "../frontend/dist/",
  63. "../frontend/",
  64. "/usr/share/OliveTin/frontend/",
  65. "/var/www/OliveTin/",
  66. "/var/www/olivetin/",
  67. "/etc/OliveTin/frontend/",
  68. }
  69. dir, err := dirs.GetFirstExistingDirectory("webui", directoriesToSearch)
  70. if err != nil {
  71. log.Warnf("Did not find the webui directory, you will probably get 404 errors.")
  72. return "./webui" // Should not exist
  73. }
  74. log.Infof("Using webui directory: %s", dir)
  75. return dir
  76. }
  77. func (s *webUIServer) findCustomWebuiDir() string {
  78. dir := path.Join(s.cfg.GetDir(), "custom-webui")
  79. return dir
  80. }
  81. func (s *webUIServer) setupCustomWebuiDir() {
  82. dir := s.findCustomWebuiDir()
  83. err := os.MkdirAll(path.Join(dir, "themes/"), 0775)
  84. if err != nil {
  85. log.Warnf("Could not create themes directory: %v", err)
  86. sv.Set("internal.themesdir", err.Error())
  87. } else {
  88. sv.Set("internal.themesdir", dir)
  89. }
  90. }
  91. func (s *webUIServer) generateThemeCss(w http.ResponseWriter, r *http.Request) {
  92. themeCssFilename := path.Join(s.findCustomWebuiDir(), "themes", s.cfg.ThemeName, "theme.css")
  93. if !customThemeCssRead || s.cfg.ThemeCacheDisabled {
  94. customThemeCssRead = true
  95. if _, err := os.Stat(themeCssFilename); err == nil {
  96. customThemeCss, _ = os.ReadFile(themeCssFilename)
  97. } else {
  98. log.Debugf("Theme CSS not read: %v", err)
  99. customThemeCss = []byte("/* not found */")
  100. }
  101. }
  102. w.Header().Add("Content-Type", "text/css")
  103. w.Write(customThemeCss)
  104. }
  105. type publicOAuth2Provider struct {
  106. Name string
  107. Title string
  108. Icon string
  109. }
  110. func buildPublicOAuth2ProvidersList(cfg *config.Config) []publicOAuth2Provider {
  111. var publicProviders []publicOAuth2Provider
  112. for _, provider := range cfg.AuthOAuth2Providers {
  113. publicProviders = append(publicProviders, publicOAuth2Provider{
  114. Name: provider.Name,
  115. Title: provider.Title,
  116. Icon: provider.Icon,
  117. })
  118. }
  119. return publicProviders
  120. }
  121. func (s *webUIServer) generateWebUISettings(w http.ResponseWriter, r *http.Request) {
  122. log.Infof("Generating webui settings for %s", r.RemoteAddr)
  123. jsonRet, _ := json.Marshal(webUISettings{
  124. Rest: s.cfg.ExternalRestAddress + "/api/",
  125. ShowFooter: s.cfg.ShowFooter,
  126. ShowNavigation: s.cfg.ShowNavigation,
  127. ShowNewVersions: s.cfg.ShowNewVersions,
  128. AvailableVersion: installationinfo.Runtime.AvailableVersion,
  129. CurrentVersion: installationinfo.Build.Version,
  130. PageTitle: s.cfg.PageTitle,
  131. SectionNavigationStyle: s.cfg.SectionNavigationStyle,
  132. DefaultIconForBack: s.cfg.DefaultIconForBack,
  133. EnableCustomJs: s.cfg.EnableCustomJs,
  134. AuthLoginUrl: s.cfg.AuthLoginUrl,
  135. AuthLocalLogin: s.cfg.AuthLocalUsers.Enabled,
  136. AuthOAuth2Providers: buildPublicOAuth2ProvidersList(s.cfg),
  137. AdditionalLinks: s.cfg.AdditionalNavigationLinks,
  138. StyleMods: s.cfg.StyleMods,
  139. })
  140. w.Header().Add("Content-Type", "application/json")
  141. _, err := w.Write([]byte(jsonRet))
  142. if err != nil {
  143. log.Warnf("Could not write webui settings: %v", err)
  144. }
  145. }
  146. func (s *webUIServer) handleCustomWebui() (http.Handler) {
  147. return http.StripPrefix("/custom-webui/", http.FileServer(http.Dir(s.findCustomWebuiDir())))
  148. }