diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c2f0fbafb36..893be42f479 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -92,13 +92,16 @@ jobs: docker exec -t build /bin/bash -c "make build-cc-linux-arm32v6" docker exec -t build /bin/bash -c "make build-cc-freebsd" + - name: Zip UI + run: docker exec -t build /bin/bash -c "make zip-ui" + - name: Cleanup build container run: docker rm -f -v build - name: Generate checksums run: | git describe --tags --exclude latest_develop | tee CHECKSUMS_SHA1 - sha1sum dist/Stash.app.zip dist/stash-* | sed 's/dist\///g' | tee -a CHECKSUMS_SHA1 + sha1sum dist/Stash.app.zip dist/stash-* dist/stash-ui.zip | sed 's/dist\///g' | tee -a CHECKSUMS_SHA1 echo "STASH_VERSION=$(git describe --tags --exclude latest_develop)" >> $GITHUB_ENV echo "RELEASE_DATE=$(date +'%Y-%m-%d %H:%M:%S %Z')" >> $GITHUB_ENV @@ -126,6 +129,14 @@ jobs: name: stash-linux path: dist/stash-linux + - name: Upload UI + # only upload for pull requests + if: ${{ github.event_name == 'pull_request' && github.base_ref != 'refs/heads/develop' && github.base_ref != 'refs/heads/master'}} + uses: actions/upload-artifact@v2 + with: + name: stash-ui.zip + path: dist/stash-ui.zip + - name: Update latest_develop tag if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' }} run : git tag -f latest_develop; git push -f --tags @@ -147,6 +158,7 @@ jobs: dist/stash-linux-arm32v7 dist/stash-linux-arm32v6 dist/stash-freebsd + dist/stash-ui.zip CHECKSUMS_SHA1 - name: Master release @@ -166,6 +178,7 @@ jobs: dist/stash-linux-arm32v7 dist/stash-linux-arm32v6 dist/stash-freebsd + dist/stash-ui.zip CHECKSUMS_SHA1 gzip: false diff --git a/Makefile b/Makefile index b4c8dfbeaf9..237f48557ab 100644 --- a/Makefile +++ b/Makefile @@ -353,6 +353,11 @@ endif ui: ui-env cd ui/v2.5 && yarn build +.PHONY: zip-ui +zip-ui: + rm -f dist/stash-ui.zip + cd ui/v2.5/build && zip -r ../../../dist/stash-ui.zip . + .PHONY: ui-start ui-start: ui-env cd ui/v2.5 && yarn start --host diff --git a/internal/api/server.go b/internal/api/server.go index d563243e2da..b9fd1eeed8c 100644 --- a/internal/api/server.go +++ b/internal/api/server.go @@ -53,6 +53,28 @@ type Server struct { manager *manager.Manager } +// TODO - os.DirFS doesn't implement ReadDir, so re-implement it here +// This can be removed when we upgrade go +type osFS string + +func (dir osFS) ReadDir(name string) ([]os.DirEntry, error) { + fullname := string(dir) + "/" + name + entries, err := os.ReadDir(fullname) + if err != nil { + var e *os.PathError + if errors.As(err, &e) { + // See comment in dirFS.Open. + e.Path = name + } + return nil, err + } + return entries, nil +} + +func (dir osFS) Open(name string) (fs.File, error) { + return os.DirFS(string(dir)).Open(name) +} + // Called at startup func Initialize() (*Server, error) { mgr := manager.GetInstance() @@ -213,25 +235,31 @@ func Initialize() (*Server, error) { r.Mount("/custom", getCustomRoutes(customServedFolders)) } - customUILocation := cfg.GetCustomUILocation() - staticUI := statigz.FileServer(ui.UIBox.(fs.ReadDirFS)) + var uiFS fs.FS + var staticUI *statigz.Server + customUILocation := cfg.GetUILocation() + if customUILocation != "" { + logger.Debugf("Serving UI from %s", customUILocation) + uiFS = osFS(customUILocation) + staticUI = statigz.FileServer(uiFS.(fs.ReadDirFS)) + } else { + logger.Debug("Serving embedded UI") + uiFS = ui.UIBox + staticUI = statigz.FileServer(ui.UIBox.(fs.ReadDirFS)) + } // Serve the web app r.HandleFunc("/*", func(w http.ResponseWriter, r *http.Request) { ext := path.Ext(r.URL.Path) - if customUILocation != "" { - if r.URL.Path == "index.html" || ext == "" { - r.URL.Path = "/" - } - - http.FileServer(http.Dir(customUILocation)).ServeHTTP(w, r) - return + if ext == ".html" || ext == "" { + w.Header().Set("Content-Type", "text/html") + setPageSecurityHeaders(w, r, pluginCache.ListPlugins()) } - if ext == ".html" || ext == "" { + if ext == "" || r.URL.Path == "/" || r.URL.Path == "/index.html" { themeColor := cfg.GetThemeColor() - data, err := fs.ReadFile(ui.UIBox, "index.html") + data, err := fs.ReadFile(uiFS, "index.html") if err != nil { panic(err) } @@ -241,9 +269,6 @@ func Initialize() (*Server, error) { indexHtml = strings.ReplaceAll(indexHtml, "%COLOR%", themeColor) indexHtml = strings.Replace(indexHtml, `