From 58f41085dd6ce089701fc8b738cd748d63f87718 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Else Date: Tue, 16 Feb 2021 21:27:52 +0100 Subject: [PATCH] Add CSP and rework speak.js --- config.go | 21 +++++++------ http.go | 13 +++++++- templates/assets/js/speak.js | 60 ++++++++++++++++-------------------- templates/postactions.gohtml | 3 +- 4 files changed, 50 insertions(+), 47 deletions(-) diff --git a/config.go b/config.go index e855019..c8084c8 100644 --- a/config.go +++ b/config.go @@ -23,16 +23,17 @@ type config struct { } type configServer struct { - Logging bool `mapstructure:"logging"` - LogFile string `mapstructure:"logFile"` - Debug bool `mapstructure:"Debug"` - Port int `mapstructure:"port"` - PublicAddress string `mapstructure:"publicAddress"` - ShortPublicAddress string `mapstructure:"shortPublicAddress"` - PublicHTTPS bool `mapstructure:"publicHttps"` - SecurityHeaders bool `mapstructure:"securityHeaders"` - LetsEncryptMail string `mapstructure:"letsEncryptMail"` - JWTSecret string `mapstructure:"jwtSecret"` + Logging bool `mapstructure:"logging"` + LogFile string `mapstructure:"logFile"` + Debug bool `mapstructure:"Debug"` + Port int `mapstructure:"port"` + PublicAddress string `mapstructure:"publicAddress"` + ShortPublicAddress string `mapstructure:"shortPublicAddress"` + PublicHTTPS bool `mapstructure:"publicHttps"` + SecurityHeaders bool `mapstructure:"securityHeaders"` + CSPDomains []string `mapstructure:"cspDomains"` + LetsEncryptMail string `mapstructure:"letsEncryptMail"` + JWTSecret string `mapstructure:"jwtSecret"` publicHostname string shortPublicHostname string } diff --git a/http.go b/http.go index 6a012ef..b8572e9 100644 --- a/http.go +++ b/http.go @@ -4,7 +4,9 @@ import ( "compress/flate" "fmt" "net/http" + "net/url" "strconv" + "strings" "sync/atomic" "github.com/caddyserver/certmagic" @@ -388,13 +390,22 @@ func buildHandler() (http.Handler, error) { } func securityHeaders(next http.Handler) http.Handler { + extraCSPDomains := "" + if mp := appConfig.Micropub.MediaStorage; mp != nil && mp.MediaURL != "" { + if u, err := url.Parse(mp.MediaURL); err == nil { + extraCSPDomains += " " + u.Hostname() + } + } + if len(appConfig.Server.CSPDomains) > 0 { + extraCSPDomains += " " + strings.Join(appConfig.Server.CSPDomains, " ") + } return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Add("Strict-Transport-Security", "max-age=31536000;") w.Header().Add("Referrer-Policy", "no-referrer") w.Header().Add("X-Content-Type-Options", "nosniff") w.Header().Add("X-Frame-Options", "SAMEORIGIN") w.Header().Add("X-Xss-Protection", "1; mode=block") - // TODO: Add CSP + w.Header().Add("Content-Security-Policy", "default-src 'self'"+extraCSPDomains) next.ServeHTTP(w, r) }) } diff --git a/templates/assets/js/speak.js b/templates/assets/js/speak.js index 18f0911..4a5b408 100644 --- a/templates/assets/js/speak.js +++ b/templates/assets/js/speak.js @@ -1,45 +1,37 @@ "use strict"; -function getVoice() { - if (window.speechSynthesis) { - return window.speechSynthesis.getVoices().filter(voice => voice.lang.startsWith(document.querySelector('html').lang))[0]; - } - return false; +let sb = document.getElementById('speakBtn') +let s = window.speechSynthesis + +function gv() { + return s ? s.getVoices().filter(voice => voice.lang.startsWith(document.querySelector('html').lang))[0] : false } -function initSpeak() { - if (window.speechSynthesis) { - let speakBtn = document.querySelector('#speakBtn'); - speakBtn.style.display = ''; - speakBtn.onclick = function() { speak() }; - speakBtn.textContent = speakText; +function is() { + if (s) { + sb.classList.remove('hide') + sb.onclick = sp + sb.textContent = sb.dataset.speak } } -function speak() { - console.log("Start speaking") - let speakBtn = document.querySelector('#speakBtn'); - speakBtn.onclick = function() { stopSpeak() }; - speakBtn.textContent = stopSpeakText; - let textContent = - ((document.querySelector('article .p-name')) ? document.querySelector('article .p-name').innerText + "\n\n" : "") - + document.querySelector('article .e-content').innerText; - let utterThis = new SpeechSynthesisUtterance(textContent); - utterThis.voice = getVoice(); - utterThis.onerror = stopSpeak; - utterThis.onend = stopSpeak; - window.speechSynthesis.speak(utterThis); +function sp() { + sb.onclick = ssp + sb.textContent = sb.dataset.stopspeak + let ut = new SpeechSynthesisUtterance( + ((document.querySelector('article .p-name')) ? document.querySelector('article .p-name').innerText + "\n\n" : '') + document.querySelector('article .e-content').innerText + ) + ut.voice = gv() + ut.onerror = ssp + ut.onend = ssp + s.speak(ut) } -function stopSpeak() { - console.log("Stop speaking") - window.speechSynthesis.cancel(); - let speakBtn = document.querySelector('#speakBtn'); - speakBtn.onclick = function() { speak() }; - speakBtn.textContent = speakText; +function ssp() { + s.cancel() + sb.onclick = sp + sb.textContent = sb.dataset.speak } -window.onbeforeunload = function () { - stopSpeak(); -} -initSpeak(); \ No newline at end of file +window.onbeforeunload = ssp +is() \ No newline at end of file diff --git a/templates/postactions.gohtml b/templates/postactions.gohtml index a9511d5..2cfedd0 100644 --- a/templates/postactions.gohtml +++ b/templates/postactions.gohtml @@ -1,8 +1,7 @@ {{ define "postactions" }}
{{ string .Blog.Lang "share" }}  - - +
{{ end }} \ No newline at end of file