diff --git a/internal/ui/static/static.go b/internal/ui/static/static.go index 48a8c70a..72c2df36 100644 --- a/internal/ui/static/static.go +++ b/internal/ui/static/static.go @@ -15,12 +15,16 @@ import ( "github.com/tdewolff/minify/v2/js" ) +type asset struct { + Data []byte + Checksum string +} + // Static assets. var ( - StylesheetBundleChecksums map[string]string - StylesheetBundles map[string][]byte - JavascriptBundleChecksums map[string]string - JavascriptBundles map[string][]byte + StylesheetBundles map[string]asset + JavascriptBundles map[string]asset + binaryFileChecksums map[string]string ) //go:embed bin/* @@ -32,16 +36,13 @@ var stylesheetFiles embed.FS //go:embed js/*.js var javascriptFiles embed.FS -var binaryFileChecksums map[string]string - // CalculateBinaryFileChecksums generates hash of embed binary files. func CalculateBinaryFileChecksums() error { - binaryFileChecksums = make(map[string]string) - dirEntries, err := binaryFiles.ReadDir("bin") if err != nil { return err } + binaryFileChecksums = make(map[string]string, len(dirEntries)) for _, dirEntry := range dirEntries { data, err := LoadBinaryFile(dirEntry.Name()) @@ -57,15 +58,16 @@ func CalculateBinaryFileChecksums() error { // LoadBinaryFile loads an embed binary file. func LoadBinaryFile(filename string) ([]byte, error) { - return binaryFiles.ReadFile(fmt.Sprintf(`bin/%s`, filename)) + return binaryFiles.ReadFile("bin/" + filename) } // GetBinaryFileChecksum returns a binary file checksum. func GetBinaryFileChecksum(filename string) (string, error) { - if _, found := binaryFileChecksums[filename]; !found { + data, found := binaryFileChecksums[filename] + if !found { return "", fmt.Errorf(`static: unable to find checksum for %q`, filename) } - return binaryFileChecksums[filename], nil + return data, nil } // GenerateStylesheetsBundles creates CSS bundles. @@ -79,8 +81,7 @@ func GenerateStylesheetsBundles() error { "system_sans_serif": {"css/system.css", "css/sans_serif.css", "css/common.css"}, } - StylesheetBundles = make(map[string][]byte) - StylesheetBundleChecksums = make(map[string]string) + StylesheetBundles = make(map[string]asset, len(bundles)) minifier := minify.New() minifier.AddFunc("text/css", css.Minify) @@ -102,8 +103,10 @@ func GenerateStylesheetsBundles() error { return err } - StylesheetBundles[bundle] = minifiedData - StylesheetBundleChecksums[bundle] = crypto.HashFromBytes(minifiedData) + StylesheetBundles[bundle] = asset{ + Data: minifiedData, + Checksum: crypto.HashFromBytes(minifiedData), + } } return nil @@ -125,8 +128,7 @@ func GenerateJavascriptBundles() error { }, } - JavascriptBundles = make(map[string][]byte) - JavascriptBundleChecksums = make(map[string]string) + JavascriptBundles = make(map[string]asset, len(bundles)) jsMinifier := js.Minifier{Version: 2020} @@ -150,8 +152,10 @@ func GenerateJavascriptBundles() error { return err } - JavascriptBundles[bundle] = minifiedData - JavascriptBundleChecksums[bundle] = crypto.HashFromBytes(minifiedData) + JavascriptBundles[bundle] = asset{ + Data: minifiedData, + Checksum: crypto.HashFromBytes(minifiedData), + } } return nil diff --git a/internal/ui/static_javascript.go b/internal/ui/static_javascript.go index 36061ce9..aff42c6d 100644 --- a/internal/ui/static_javascript.go +++ b/internal/ui/static_javascript.go @@ -21,14 +21,14 @@ const licenseSuffix = "\n//@license-end" func (h *handler) showJavascript(w http.ResponseWriter, r *http.Request) { filename := request.RouteStringParam(r, "name") - etag, found := static.JavascriptBundleChecksums[filename] + js, found := static.JavascriptBundles[filename] if !found { html.NotFound(w, r) return } - response.New(w, r).WithCaching(etag, 48*time.Hour, func(b *response.Builder) { - contents := static.JavascriptBundles[filename] + response.New(w, r).WithCaching(js.Checksum, 48*time.Hour, func(b *response.Builder) { + contents := js.Data if filename == "service-worker" { variables := fmt.Sprintf(`const OFFLINE_URL=%q;`, route.Path(h.router, "offline")) diff --git a/internal/ui/static_stylesheet.go b/internal/ui/static_stylesheet.go index f37732ee..9b07373b 100644 --- a/internal/ui/static_stylesheet.go +++ b/internal/ui/static_stylesheet.go @@ -15,15 +15,15 @@ import ( func (h *handler) showStylesheet(w http.ResponseWriter, r *http.Request) { filename := request.RouteStringParam(r, "name") - etag, found := static.StylesheetBundleChecksums[filename] + m, found := static.StylesheetBundles[filename] if !found { html.NotFound(w, r) return } - response.New(w, r).WithCaching(etag, 48*time.Hour, func(b *response.Builder) { + response.New(w, r).WithCaching(m.Checksum, 48*time.Hour, func(b *response.Builder) { b.WithHeader("Content-Type", "text/css; charset=utf-8") - b.WithBody(static.StylesheetBundles[filename]) + b.WithBody(m.Data) b.Write() }) } diff --git a/internal/ui/view/view.go b/internal/ui/view/view.go index 742bb3a9..acccabd7 100644 --- a/internal/ui/view/view.go +++ b/internal/ui/view/view.go @@ -41,10 +41,10 @@ func New(tpl *template.Engine, r *http.Request, sess *session.Session) *View { "flashErrorMessage": sess.FlashErrorMessage(request.FlashErrorMessage(r)), "theme": theme, "language": request.UserLanguage(r), - "theme_checksum": static.StylesheetBundleChecksums[theme], - "app_js_checksum": static.JavascriptBundleChecksums["app"], - "sw_js_checksum": static.JavascriptBundleChecksums["service-worker"], - "webauthn_js_checksum": static.JavascriptBundleChecksums["webauthn"], + "theme_checksum": static.StylesheetBundles[theme].Checksum, + "app_js_checksum": static.JavascriptBundles["app"].Checksum, + "sw_js_checksum": static.JavascriptBundles["service-worker"].Checksum, + "webauthn_js_checksum": static.JavascriptBundles["webauthn"].Checksum, "webAuthnEnabled": config.Opts.WebAuthn(), }} }