Add CSP and rework speak.js

This commit is contained in:
Jan-Lukas Else 2021-02-16 21:27:52 +01:00
parent 99789efcd3
commit 58f41085dd
4 changed files with 50 additions and 47 deletions

View File

@ -23,16 +23,17 @@ type config struct {
} }
type configServer struct { type configServer struct {
Logging bool `mapstructure:"logging"` Logging bool `mapstructure:"logging"`
LogFile string `mapstructure:"logFile"` LogFile string `mapstructure:"logFile"`
Debug bool `mapstructure:"Debug"` Debug bool `mapstructure:"Debug"`
Port int `mapstructure:"port"` Port int `mapstructure:"port"`
PublicAddress string `mapstructure:"publicAddress"` PublicAddress string `mapstructure:"publicAddress"`
ShortPublicAddress string `mapstructure:"shortPublicAddress"` ShortPublicAddress string `mapstructure:"shortPublicAddress"`
PublicHTTPS bool `mapstructure:"publicHttps"` PublicHTTPS bool `mapstructure:"publicHttps"`
SecurityHeaders bool `mapstructure:"securityHeaders"` SecurityHeaders bool `mapstructure:"securityHeaders"`
LetsEncryptMail string `mapstructure:"letsEncryptMail"` CSPDomains []string `mapstructure:"cspDomains"`
JWTSecret string `mapstructure:"jwtSecret"` LetsEncryptMail string `mapstructure:"letsEncryptMail"`
JWTSecret string `mapstructure:"jwtSecret"`
publicHostname string publicHostname string
shortPublicHostname string shortPublicHostname string
} }

13
http.go
View File

@ -4,7 +4,9 @@ import (
"compress/flate" "compress/flate"
"fmt" "fmt"
"net/http" "net/http"
"net/url"
"strconv" "strconv"
"strings"
"sync/atomic" "sync/atomic"
"github.com/caddyserver/certmagic" "github.com/caddyserver/certmagic"
@ -388,13 +390,22 @@ func buildHandler() (http.Handler, error) {
} }
func securityHeaders(next http.Handler) http.Handler { 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) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Strict-Transport-Security", "max-age=31536000;") w.Header().Add("Strict-Transport-Security", "max-age=31536000;")
w.Header().Add("Referrer-Policy", "no-referrer") w.Header().Add("Referrer-Policy", "no-referrer")
w.Header().Add("X-Content-Type-Options", "nosniff") w.Header().Add("X-Content-Type-Options", "nosniff")
w.Header().Add("X-Frame-Options", "SAMEORIGIN") w.Header().Add("X-Frame-Options", "SAMEORIGIN")
w.Header().Add("X-Xss-Protection", "1; mode=block") 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) next.ServeHTTP(w, r)
}) })
} }

View File

@ -1,45 +1,37 @@
"use strict"; "use strict";
function getVoice() { let sb = document.getElementById('speakBtn')
if (window.speechSynthesis) { let s = window.speechSynthesis
return window.speechSynthesis.getVoices().filter(voice => voice.lang.startsWith(document.querySelector('html').lang))[0];
} function gv() {
return false; return s ? s.getVoices().filter(voice => voice.lang.startsWith(document.querySelector('html').lang))[0] : false
} }
function initSpeak() { function is() {
if (window.speechSynthesis) { if (s) {
let speakBtn = document.querySelector('#speakBtn'); sb.classList.remove('hide')
speakBtn.style.display = ''; sb.onclick = sp
speakBtn.onclick = function() { speak() }; sb.textContent = sb.dataset.speak
speakBtn.textContent = speakText;
} }
} }
function speak() { function sp() {
console.log("Start speaking") sb.onclick = ssp
let speakBtn = document.querySelector('#speakBtn'); sb.textContent = sb.dataset.stopspeak
speakBtn.onclick = function() { stopSpeak() }; let ut = new SpeechSynthesisUtterance(
speakBtn.textContent = stopSpeakText; ((document.querySelector('article .p-name')) ? document.querySelector('article .p-name').innerText + "\n\n" : '') + document.querySelector('article .e-content').innerText
let textContent = )
((document.querySelector('article .p-name')) ? document.querySelector('article .p-name').innerText + "\n\n" : "") ut.voice = gv()
+ document.querySelector('article .e-content').innerText; ut.onerror = ssp
let utterThis = new SpeechSynthesisUtterance(textContent); ut.onend = ssp
utterThis.voice = getVoice(); s.speak(ut)
utterThis.onerror = stopSpeak;
utterThis.onend = stopSpeak;
window.speechSynthesis.speak(utterThis);
} }
function stopSpeak() { function ssp() {
console.log("Stop speaking") s.cancel()
window.speechSynthesis.cancel(); sb.onclick = sp
let speakBtn = document.querySelector('#speakBtn'); sb.textContent = sb.dataset.speak
speakBtn.onclick = function() { speak() };
speakBtn.textContent = speakText;
} }
window.onbeforeunload = function () { window.onbeforeunload = ssp
stopSpeak(); is()
}
initSpeak();

View File

@ -1,8 +1,7 @@
{{ define "postactions" }} {{ define "postactions" }}
<div class="p flex" id="post-actions"> <div class="p flex" id="post-actions">
<a href="https://www.addtoany.com/share#url={{ absolute .Data.Path }}{{ with title .Data }}&title={{ . }}{{ end }}" target="_blank" rel="nofollow noopener noreferrer" class="button invert">{{ string .Blog.Lang "share" }}</a>&nbsp; <a href="https://www.addtoany.com/share#url={{ absolute .Data.Path }}{{ with title .Data }}&title={{ . }}{{ end }}" target="_blank" rel="nofollow noopener noreferrer" class="button invert">{{ string .Blog.Lang "share" }}</a>&nbsp;
<button id="speakBtn" class="invert" style="display: none;"></button> <button id="speakBtn" class="button invert hide" data-speak="{{ string .Blog.Lang "speak" }}" data-stopspeak="{{ string .Blog.Lang "stopspeak" }}"></button>
<script>const speakText = "{{ string .Blog.Lang "speak" }}";const stopSpeakText = "{{ string .Blog.Lang "stopspeak" }}";</script>
<script defer src="{{ asset "js/speak.js" }}"></script> <script defer src="{{ asset "js/speak.js" }}"></script>
</div> </div>
{{ end }} {{ end }}