mirror of https://github.com/jlelse/GoBlog
Add CSP and rework speak.js
This commit is contained in:
parent
99789efcd3
commit
58f41085dd
21
config.go
21
config.go
|
@ -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
13
http.go
|
@ -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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
|
|
@ -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>
|
<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>
|
||||||
<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 }}
|
Loading…
Reference in New Issue