diff --git a/pkg/server/handler.go b/pkg/server/handler.go index 4d79fcc..b509852 100644 --- a/pkg/server/handler.go +++ b/pkg/server/handler.go @@ -73,6 +73,9 @@ func staticHandler(ctx *Context) { err = ctx.Write(ctx.Srv.res["bootstrap.css"]) case "/custom.css": err = ctx.Write(ctx.Srv.res["custom.css"]) + case "/favicon.ico": + ctx.SetHeader("Content-Type", "image/x-icon") + err = ctx.Write(ctx.Srv.res["favicon.ico"]) } if err != nil { log.Println("static:", err) diff --git a/pkg/server/routes.go b/pkg/server/routes.go index 580f359..563c351 100644 --- a/pkg/server/routes.go +++ b/pkg/server/routes.go @@ -14,6 +14,11 @@ var routes = []route{ indexHandler, []string{"GET"}, }, + { + "/favicon.ico", + staticHandler, + []string{"GET"}, + }, { "/bootstrap.css", staticHandler, diff --git a/pkg/server/templates.go b/pkg/server/templates.go index 4f898b8..4e3b71c 100644 --- a/pkg/server/templates.go +++ b/pkg/server/templates.go @@ -6,6 +6,7 @@ package server import ( + "encoding/base64" "errors" "git.giftfish.de/ston1th/gowiki/pkg/log" "html/template" @@ -33,6 +34,7 @@ const ( GoWiki | {{.Title}} + @@ -871,10 +873,11 @@ html, body, .container, .content { height: 50px; color: #888888; }` + favicon = "AAABAAIAICAAAAEAIACoEAAAJgAAABAQAAABACAAaAQAAM4QAAAoAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBaNSJ/Wjf/f1o3/39aN/+AWThyAAAAAAAA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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////4P4P/+D+D//gfgf/wHwH/8B8B//APAf/gDgD/4A4A/+BOAP/gRAR/wEQMf8DEDH/A4A4/gOAeP4HgHj+B8B8/AfA/HwPwPxwA+DwH/////////////////////////////////////KAAAABAAAAAgAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgAACf1o36YBaN+YAAAABAAAAAAAAAACAWzdwf1o3/35bNl8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgFk3PH9aN/9/Wjf/gFs3OAAAAAAAAAAAf1o3wX9aN/9/WjevAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH9aN4t/Wjf/gFo39oBaNogAAAAAgFkzFIBaN/x/Wjf/f1o35XFVOQkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAWjfaf1o3/39ZOImAWjjKAAAAAH5ZN2F/Wjf/f1o38X5bN3l+WjdPAAAAAAAAAAAAAAAAAAAAAAAAAACAWzcqf1o3/39aN/+AWDY0f1o3rYBZOSh/WTexf1o3/4BaOKp8VzojgFo3ngAAAAAAAAAAAAAAAAAAAAAAAAAAgFo2en9aN/9/WjfjAAAAAH5ZN2GAWjeCgFo39n9aN/+AWjZeAAAAAIBaNsBVVVUDAAAAAAAAAAAAAAAAAAAAAH9aN8l/Wjf/gFo3lAAAAACAXToWgFo39H9aN/9/Wjf9gFkzFAAAAACAWzaEfVk5PwAAAAAAAAAAAAAAAIBYOxqAWjf+f1o3/35bNUMAAAAAAAAAAIBaOMp/Wjf/gFo3xgAAAAAAAAAAgFg2NH9ZN48AAAAAAAAAAIBbNxx/Wjf/f1o3/39aN/9/Wjf/gFVADAAAAACAWTd+f1o3/35bN3kAAAAAgFU1GH9aN/9/Wjf/gFk4oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//wAA//8AAP//AAD//wAA4Y8AAOGPAADhBwAA4QcAAMAHAADEEwAAxBMAAIYzAAACIQAA//8AAP//AAD//wAA" ) func (s *HTTPServer) loadTemplates() { - var errf bool + var fatal bool s.templ = make(map[string]*template.Template) s.res = make(map[string][]byte) parse := func(html ...string) (temp *template.Template) { @@ -884,7 +887,7 @@ func (s *HTTPServer) loadTemplates() { temp, err = temp.Parse(s) if err != nil { log.Println("parse:", err) - errf = true + fatal = true return } } @@ -894,6 +897,12 @@ func (s *HTTPServer) loadTemplates() { // resources s.res["bootstrap.css"] = []byte(bootstrapCSS) s.res["custom.css"] = []byte(customCSS) + fav, err := base64.StdEncoding.DecodeString(favicon) + if err != nil { + log.Println("favicon:", err) + fatal = true + } + s.res["favicon.ico"] = fav // pages s.templ["notFoundHandler"] = parse(index, menu, notFound) @@ -919,7 +928,7 @@ func (s *HTTPServer) loadTemplates() { // totp s.templ["userTotpHandler"] = parse(index, menu, userTotp) - if errf { + if fatal { log.Fatal("parse: ", errors.New("parsing templates failed")) } } diff --git a/sri.sh b/sri.sh index 6ebb04e..e71b9e1 100755 --- a/sri.sh +++ b/sri.sh @@ -3,7 +3,8 @@ HASH="sha256" DIR="templates" -FILES="*.css *.js *.ico" +FILES="*.css *.js" +BINS="*.ico" echo "SRI (subresource integrity) hashes" cd ${DIR} for f in $(ls ${FILES} 2>/dev/null); do @@ -12,3 +13,7 @@ for f in $(ls ${FILES} 2>/dev/null); do printf "%13s: " ${f} echo "${HASH}-$(cat ${f}|openssl dgst -${HASH} -binary|openssl enc -base64 -A)" done +for f in $(ls ${BINS} 2>/dev/null); do + printf "%13s: " ${f} + echo "${HASH}-$(cat ${f}|openssl dgst -${HASH} -binary|openssl enc -base64 -A)" +done diff --git a/templates.sh b/templates.sh index ed93b6c..02ce429 100755 --- a/templates.sh +++ b/templates.sh @@ -22,6 +22,7 @@ cat << EOF > ${templates_go} package server import ( + "encoding/base64" "errors" "git.giftfish.de/ston1th/gowiki/pkg/log" "html/template" @@ -43,11 +44,13 @@ for f in $(ls templates/*.css); do echo " ${fname} = \`$(cat ${f})\`" >> ${templates_go} done +echo " favicon = \"$(base64 -w 0 templates/favicon.ico)\"" >> ${templates_go} + cat << EOF >> ${templates_go} ) func (s *HTTPServer) loadTemplates() { - var errf bool + var fatal bool s.templ = make(map[string]*template.Template) s.res = make(map[string][]byte) parse := func(html ...string) (temp *template.Template) { @@ -57,7 +60,7 @@ func (s *HTTPServer) loadTemplates() { temp, err = temp.Parse(s) if err != nil { log.Println("parse:", err) - errf = true + fatal = true return } } @@ -67,6 +70,12 @@ func (s *HTTPServer) loadTemplates() { // resources s.res["bootstrap.css"] = []byte(bootstrapCSS) s.res["custom.css"] = []byte(customCSS) + fav, err := base64.StdEncoding.DecodeString(favicon) + if err != nil { + log.Println("favicon:", err) + fatal = true + } + s.res["favicon.ico"] = fav // pages s.templ["notFoundHandler"] = parse(index, menu, notFound) @@ -92,7 +101,7 @@ func (s *HTTPServer) loadTemplates() { // totp s.templ["userTotpHandler"] = parse(index, menu, userTotp) - if errf { + if fatal { log.Fatal("parse: ", errors.New("parsing templates failed")) } } diff --git a/templates/favicon.ico b/templates/favicon.ico new file mode 100644 index 0000000..a8a1b4e Binary files /dev/null and b/templates/favicon.ico differ diff --git a/templates/index.html b/templates/index.html index a305035..a467c37 100644 --- a/templates/index.html +++ b/templates/index.html @@ -2,6 +2,7 @@ GoWiki | {{.Title}} +