diff --git a/server/common/plugin.go b/server/common/plugin.go index 2023b5aa..26ebf32d 100644 --- a/server/common/plugin.go +++ b/server/common/plugin.go @@ -1,6 +1,7 @@ package common import ( + "bytes" "io" "io/fs" "net/http" @@ -223,6 +224,25 @@ func (this Get) CSS() string { return s } +var favicon struct { + binary []byte + mime string +} + +func (this Register) Favicon(binary []byte) { + favicon.binary = binary + favicon.mime = "image/svg+xml" + if bytes.HasPrefix(binary, []byte{0x00, 0x00, 0x01, 0x00}) { + favicon.mime = "image/x-icon" + } else if bytes.HasPrefix(binary, []byte{0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}) { + favicon.mime = "image/png" + } +} + +func (this Get) Favicon() ([]byte, string) { + return favicon.binary, favicon.mime +} + const OverrideVideoSourceMapper = "/overrides/video-transcoder.js" var afterload []func() diff --git a/server/ctrl/plugin.go b/server/ctrl/plugin.go index b129ae23..b2a12890 100644 --- a/server/ctrl/plugin.go +++ b/server/ctrl/plugin.go @@ -44,27 +44,27 @@ func PluginStaticHandler(ctx *App, res http.ResponseWriter, req *http.Request) { {"", ""}, } - var file io.ReadCloser - var err error + var ( + b []byte + err error + ) head := res.Header() acceptEncoding := req.Header.Get("Accept-Encoding") for _, cfg := range staticConfig { if strings.Contains(acceptEncoding, cfg.ContentType) == false { continue } - file, err = model.GetPluginFile(mux.Vars(req)["name"], path+cfg.FileExt) + b, err = model.GetPluginFile(mux.Vars(req)["name"], path+cfg.FileExt) if err != nil { - continue + break } head.Set("Content-Type", mtype) if cfg.ContentType != "" { head.Set("Content-Encoding", cfg.ContentType) } - io.Copy(res, file) - file.Close() + res.Write(b) return } - SendErrorResult(res, err) return } diff --git a/server/ctrl/static.go b/server/ctrl/static.go index dcc80bae..2dd32479 100644 --- a/server/ctrl/static.go +++ b/server/ctrl/static.go @@ -84,6 +84,11 @@ func ServeFrontofficeHandler(ctx *App, res http.ResponseWriter, req *http.Reques } func ServeFavicon(ctx *App, res http.ResponseWriter, req *http.Request) { + if binary, mime := Hooks.Get.Favicon(); len(binary) > 0 { + res.Header().Set("Content-Type", mime) + res.Write(binary) + return + } r, _ := http.NewRequest(http.MethodGet, "/favicon.svg", nil) ServeFile("/assets/logo/")(ctx, res, r) } @@ -533,13 +538,17 @@ func signature() string { } func favicon() string { - file, err := WWWPublic.Open("/assets/logo/favicon.svg") - if err != nil { - return "favicon.ico" + f, mime := Hooks.Get.Favicon() + if len(f) == 0 { + file, err := WWWPublic.Open("/assets/logo/favicon.svg") + mime = "image/svg+xml" + if err != nil { + return "favicon.ico" + } + f, err = io.ReadAll(file) + if err != nil { + return "favicon.ico" + } } - f, err := io.ReadAll(file) - if err != nil { - return "favicon.ico" - } - return "data:image/svg+xml;base64," + base64.StdEncoding.EncodeToString(f) + return "data:" + mime + ";base64," + base64.StdEncoding.EncodeToString(f) } diff --git a/server/model/plugin.go b/server/model/plugin.go index a9757783..65199f39 100644 --- a/server/model/plugin.go +++ b/server/model/plugin.go @@ -43,25 +43,23 @@ func PluginDiscovery() error { for i := 0; i < len(impl.Modules); i++ { switch impl.Modules[i]["type"] { case "css": - f, err := GetPluginFile(name, impl.Modules[i]["entrypoint"]) - if err != nil { - return err - } - b, err := io.ReadAll(f) + b, err := GetPluginFile(name, impl.Modules[i]["entrypoint"]) if err != nil { return err } Hooks.Register.CSS(string(b)) case "patch": - f, err := GetPluginFile(name, impl.Modules[i]["entrypoint"]) - if err != nil { - return err - } - b, err := io.ReadAll(f) + b, err := GetPluginFile(name, impl.Modules[i]["entrypoint"]) if err != nil { return err } Hooks.Register.StaticPatch(b) + case "favicon": + b, err := GetPluginFile(name, impl.Modules[i]["entrypoint"]) + if err != nil { + return err + } + Hooks.Register.Favicon(b) } } PLUGINS[name] = impl @@ -69,22 +67,7 @@ func PluginDiscovery() error { return nil } -type zrc struct { - f io.ReadCloser - c io.Closer -} - -func (this zrc) Read(p []byte) (n int, err error) { - return this.f.Read(p) -} - -func (this zrc) Close() error { - this.f.Close() - this.c.Close() - return nil -} - -func GetPluginFile(pluginName string, path string) (io.ReadCloser, error) { +func GetPluginFile(pluginName string, path string) ([]byte, error) { zipReader, err := zip.OpenReader(JoinPath( GetAbsolutePath(PLUGIN_PATH), pluginName+".zip", @@ -101,7 +84,13 @@ func GetPluginFile(pluginName string, path string) (io.ReadCloser, error) { zipReader.Close() return nil, err } - return zrc{f, zipReader}, nil + data, err := io.ReadAll(f) + f.Close() + zipReader.Close() + if err != nil { + return nil, err + } + return data, nil } zipReader.Close() return nil, ErrNotFound