Add SRI template rendering, move variables to template

Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
Knut Ahlers 2021-09-24 23:18:23 +02:00
parent 47d570b295
commit 85e9a2bcd1
No known key found for this signature in database
GPG Key ID: 0066F03ED215AD7D
6 changed files with 65 additions and 20 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
frontend/app.js
frontend/app.js.LICENSE.txt
frontend/css
frontend/js

View File

@ -4,8 +4,8 @@ VER_FONTAWESOME=5.14.0
default: generate download_libs
generate:
docker run --rm -i -v $(CURDIR):$(CURDIR) -w $(CURDIR)/src node:14-alpine \
make generate-inner
docker run --rm -i -v $(CURDIR):$(CURDIR) -w $(CURDIR) node:14-alpine \
sh -exc "apk add make && make -C src -f ../Makefile generate-inner"
generate-inner:
npx npm@lts ci

View File

@ -6,7 +6,11 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="css/all.min.css"/>
<link
href="css/all.min.css"
integrity="{{ SRIHash `css/all.min.css` }}"
rel="stylesheet"
>
<title>OTS - One Time Secrets</title>
@ -24,13 +28,20 @@
// Very early load of theme definition to avoid flickering
document.addEventListener('DOMContentLoaded', () => window.refreshTheme())
// Template variable from Golang process
{{- range $key, $value := .Vars }}
const {{ $key }} = "{{ $value }}"
{{- end }}
</script>
</head>
<body>
<div id="app"></div>
<script src="vars.js"></script>
<script src="app.js"></script>
<script
integrity="{{ SRIHash `app.js` }}"
src="app.js"
></script>
</body>
</html>

1
go.mod
View File

@ -7,6 +7,7 @@ require (
github.com/Luzifer/rconfig/v2 v2.2.1
github.com/gofrs/uuid/v3 v3.1.2
github.com/gorilla/mux v1.7.3
github.com/pkg/errors v0.9.1
github.com/sirupsen/logrus v1.4.2
github.com/xuyu/goredis v0.0.0-20160929021245-89fbe9474b37
)

2
go.sum
View File

@ -13,6 +13,8 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/leekchan/gtf v0.0.0-20190214083521-5fba33c5b00b/go.mod h1:thNruaSwydMhkQ8dXzapABF9Sc1Tz08ZBcDdgott9RA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=

60
main.go
View File

@ -1,6 +1,7 @@
package main
import (
"bytes"
"embed"
"fmt"
"mime"
@ -8,8 +9,10 @@ import (
"os"
"path"
"strings"
"text/template"
"github.com/gorilla/mux"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
http_helpers "github.com/Luzifer/go_helpers/v2/http"
@ -24,6 +27,8 @@ var (
VersionAndExit bool `flag:"version" default:"false" description:"Print version information and exit"`
}
cachedIndex []byte
product = "ots"
version = "dev"
)
@ -56,38 +61,66 @@ func main() {
api := newAPI(store)
r := mux.NewRouter()
r.Use(http_helpers.GzipHandler)
api.Register(r.PathPrefix("/api").Subrouter())
r.HandleFunc("/vars.js", handleVars)
r.PathPrefix("/").HandlerFunc(http_helpers.GzipFunc(assetDelivery))
r.HandleFunc("/", handleIndex)
r.PathPrefix("/").HandlerFunc(assetDelivery)
log.Fatalf("HTTP server quit: %s", http.ListenAndServe(cfg.Listen, http_helpers.NewHTTPLogHandler(r)))
}
func assetDelivery(res http.ResponseWriter, r *http.Request) {
func assetDelivery(w http.ResponseWriter, r *http.Request) {
assetName := r.URL.Path
if assetName == "/" {
assetName = "/index.html"
}
dot := strings.LastIndex(assetName, ".")
if dot < 0 {
// There are no assets with no dot in it
http.Error(res, "404 not found", http.StatusNotFound)
http.Error(w, "404 not found", http.StatusNotFound)
return
}
ext := assetName[dot:]
assetData, err := assets.ReadFile(path.Join("frontend", assetName))
if err != nil {
http.Error(res, "404 not found", http.StatusNotFound)
http.Error(w, "404 not found", http.StatusNotFound)
return
}
res.Header().Set("Content-Type", mime.TypeByExtension(ext))
res.Write(assetData)
w.Header().Set("Content-Type", mime.TypeByExtension(ext))
w.Write(assetData)
}
func handleVars(w http.ResponseWriter, r *http.Request) {
func handleIndex(w http.ResponseWriter, r *http.Request) {
if cachedIndex != nil {
w.Write(cachedIndex)
return
}
indexTpl, err := assets.ReadFile("frontend/index.html")
if err != nil {
http.Error(w, "404 not found", http.StatusNotFound)
return
}
tpl, err := template.New("index.html").Funcs(tplFuncs).Parse(string(indexTpl))
if err != nil {
http.Error(w, errors.Wrap(err, "parsing template").Error(), http.StatusInternalServerError)
return
}
buf := new(bytes.Buffer)
if err = tpl.Execute(buf, struct{ Vars map[string]string }{Vars: getJSVars(r)}); err != nil {
http.Error(w, errors.Wrap(err, "parsing template").Error(), http.StatusInternalServerError)
return
}
cachedIndex = buf.Bytes()
w.Write(buf.Bytes())
}
func getJSVars(r *http.Request) map[string]string {
cookie, _ := r.Cookie("lang")
cookieLang := ""
@ -110,10 +143,7 @@ func handleVars(w http.ResponseWriter, r *http.Request) {
vars["locale"] = defaultLang
}
w.Header().Set("Content-Type", "application/javascript")
for k, v := range vars {
fmt.Fprintf(w, "var %s = %q\n", k, v)
}
return vars
}
func normalizeLang(lang string) string {