Add initial CSP header support (currently only for images and error pageS)
This commit is contained in:
parent
b8171a535a
commit
352eb24c30
|
@ -12,6 +12,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/yosssi/gohtml"
|
"github.com/yosssi/gohtml"
|
||||||
|
"seedno.de/seednode/roulette/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -30,7 +31,11 @@ func notFound(w http.ResponseWriter, r *http.Request, path string) error {
|
||||||
w.WriteHeader(http.StatusNotFound)
|
w.WriteHeader(http.StatusNotFound)
|
||||||
w.Header().Add("Content-Type", "text/html")
|
w.Header().Add("Content-Type", "text/html")
|
||||||
|
|
||||||
_, err := io.WriteString(w, gohtml.Format(newPage("Not Found", "404 Page not found")))
|
nonce := types.GetNonce(6)
|
||||||
|
|
||||||
|
w.Header().Add("Content-Security-Policy", fmt.Sprintf("default-src 'self' 'nonce-%s';", nonce))
|
||||||
|
|
||||||
|
_, err := io.WriteString(w, gohtml.Format(newPage("Not Found", "404 Page not found", nonce)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -49,9 +54,14 @@ func notFound(w http.ResponseWriter, r *http.Request, path string) error {
|
||||||
func serverError(w http.ResponseWriter, r *http.Request, i interface{}) {
|
func serverError(w http.ResponseWriter, r *http.Request, i interface{}) {
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
w.Header().Add("Content-Type", "text/html")
|
w.Header().Add("Content-Type", "text/html")
|
||||||
|
|
||||||
io.WriteString(w, gohtml.Format(newPage("Server Error", "An error has occurred. Please try again.")))
|
nonce := types.GetNonce(6)
|
||||||
|
|
||||||
|
w.Header().Add("Content-Security-Policy", fmt.Sprintf("default-src 'self' 'nonce-%s';", nonce))
|
||||||
|
|
||||||
|
io.WriteString(w, gohtml.Format(newPage("Server Error", "An error has occurred. Please try again.", nonce)))
|
||||||
|
|
||||||
if Verbose {
|
if Verbose {
|
||||||
fmt.Printf("%s | ERROR: Invalid request for %s from %s\n",
|
fmt.Printf("%s | ERROR: Invalid request for %s from %s\n",
|
||||||
|
|
|
@ -6,6 +6,7 @@ package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -16,15 +17,15 @@ import (
|
||||||
//go:embed favicons/*
|
//go:embed favicons/*
|
||||||
var favicons embed.FS
|
var favicons embed.FS
|
||||||
|
|
||||||
const (
|
func getFavicon(nonce string) string {
|
||||||
faviconHtml string = `<link rel="apple-touch-icon" sizes="180x180" href="/favicons/apple-touch-icon.png">
|
return fmt.Sprintf(`<link rel="apple-touch-icon" sizes="180x180" href="/favicons/apple-touch-icon.png">
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicons/favicon-32x32.png">
|
<link rel="icon" type="image/png" sizes="32x32" href="/favicons/favicon-32x32.png">
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicons/favicon-16x16.png">
|
<link rel="icon" type="image/png" sizes="16x16" href="/favicons/favicon-16x16.png">
|
||||||
<link rel="manifest" href="/favicons/site.webmanifest">
|
<link rel="manifest" nonce=%q href="/favicons/site.webmanifest">
|
||||||
<link rel="mask-icon" href="/favicons/safari-pinned-tab.svg" color="#5bbad5">
|
<link rel="mask-icon" href="/favicons/safari-pinned-tab.svg" color="#5bbad5">
|
||||||
<meta name="msapplication-TileColor" content="#da532c">
|
<meta name="msapplication-TileColor" content="#da532c">
|
||||||
<meta name="theme-color" content="#ffffff">`
|
<meta name="theme-color" content="#ffffff">`, nonce)
|
||||||
)
|
}
|
||||||
|
|
||||||
func serveFavicons(errorChannel chan<- error) httprouter.Handle {
|
func serveFavicons(errorChannel chan<- error) httprouter.Handle {
|
||||||
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
||||||
|
|
|
@ -26,10 +26,11 @@ func refreshInterval(r *http.Request) (int64, string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func refreshFunction(rootUrl string, refreshTimer int64) string {
|
func refreshFunction(rootUrl string, refreshTimer int64, nonce string) string {
|
||||||
var htmlBody strings.Builder
|
var htmlBody strings.Builder
|
||||||
|
|
||||||
htmlBody.WriteString(fmt.Sprintf("<script>window.onload = function(){ clear = setInterval(function() {window.location.href = '%s';}, %d)};",
|
htmlBody.WriteString(fmt.Sprintf(`<script nonce=%q>window.addEventListener("load", function(){ clear = setInterval(function() {window.location.href = '%s';}, %d)});`,
|
||||||
|
nonce,
|
||||||
rootUrl,
|
rootUrl,
|
||||||
refreshTimer))
|
refreshTimer))
|
||||||
htmlBody.WriteString("document.body.onkeyup = function(e) { ")
|
htmlBody.WriteString("document.body.onkeyup = function(e) { ")
|
||||||
|
|
|
@ -17,7 +17,7 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AllowedCharacters string = `^[A-z0-9.\-_]+$`
|
AllowedCharacters string = `^[A-z0-9.\-_]+$`
|
||||||
ReleaseVersion string = "8.0.0"
|
ReleaseVersion string = "8.1.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
17
cmd/web.go
17
cmd/web.go
|
@ -40,12 +40,13 @@ const (
|
||||||
timeout time.Duration = 10 * time.Second
|
timeout time.Duration = 10 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
func newPage(title, body string) string {
|
func newPage(title, body, nonce string) string {
|
||||||
var htmlBody strings.Builder
|
var htmlBody strings.Builder
|
||||||
|
|
||||||
htmlBody.WriteString(`<!DOCTYPE html><html lang="en"><head>`)
|
htmlBody.WriteString(`<!DOCTYPE html><html lang="en"><head>`)
|
||||||
htmlBody.WriteString(faviconHtml)
|
htmlBody.WriteString(getFavicon(nonce))
|
||||||
htmlBody.WriteString(`<style>html,body,a{display:block;height:100%;width:100%;text-decoration:none;color:inherit;cursor:auto;}</style>`)
|
htmlBody.WriteString(fmt.Sprintf(`<style nonce=%q>`, nonce))
|
||||||
|
htmlBody.WriteString(`html,body,a{display:block;height:100%;width:100%;text-decoration:none;color:inherit;cursor:auto;}</style>`)
|
||||||
htmlBody.WriteString(fmt.Sprintf("<title>%s</title></head>", title))
|
htmlBody.WriteString(fmt.Sprintf("<title>%s</title></head>", title))
|
||||||
htmlBody.WriteString(fmt.Sprintf("<body><a href=\"/\">%s</a></body></html>", body))
|
htmlBody.WriteString(fmt.Sprintf("<body><a href=\"/\">%s</a></body></html>", body))
|
||||||
|
|
||||||
|
@ -308,6 +309,8 @@ func serveMedia(paths []string, index *fileIndex, filename *regexp.Regexp, forma
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nonce := format.CSP(w)
|
||||||
|
|
||||||
mediaType := format.MediaType(filepath.Ext(path))
|
mediaType := format.MediaType(filepath.Ext(path))
|
||||||
|
|
||||||
fileUri := Prefix + generateFileUri(path)
|
fileUri := Prefix + generateFileUri(path)
|
||||||
|
@ -324,8 +327,8 @@ func serveMedia(paths []string, index *fileIndex, filename *regexp.Regexp, forma
|
||||||
|
|
||||||
var htmlBody strings.Builder
|
var htmlBody strings.Builder
|
||||||
htmlBody.WriteString(`<!DOCTYPE html><html class="bg" lang="en"><head>`)
|
htmlBody.WriteString(`<!DOCTYPE html><html class="bg" lang="en"><head>`)
|
||||||
htmlBody.WriteString(faviconHtml)
|
htmlBody.WriteString(getFavicon(nonce))
|
||||||
htmlBody.WriteString(fmt.Sprintf(`<style>%s</style>`, format.Css()))
|
htmlBody.WriteString(fmt.Sprintf(`<style nonce=%q>%s</style>`, nonce, format.CSS()))
|
||||||
|
|
||||||
title, err := format.Title(rootUrl, fileUri, path, fileName, Prefix, mediaType)
|
title, err := format.Title(rootUrl, fileUri, path, fileName, Prefix, mediaType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -365,10 +368,10 @@ func serveMedia(paths []string, index *fileIndex, filename *regexp.Regexp, forma
|
||||||
}
|
}
|
||||||
|
|
||||||
if refreshInterval != "0ms" {
|
if refreshInterval != "0ms" {
|
||||||
htmlBody.WriteString(refreshFunction(rootUrl, refreshTimer))
|
htmlBody.WriteString(refreshFunction(rootUrl, refreshTimer, nonce))
|
||||||
}
|
}
|
||||||
|
|
||||||
body, err := format.Body(rootUrl, fileUri, path, fileName, Prefix, mediaType)
|
body, err := format.Body(rootUrl, fileUri, path, fileName, Prefix, mediaType, nonce)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorChannel <- err
|
errorChannel <- err
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ package audio
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"seedno.de/seednode/roulette/types"
|
"seedno.de/seednode/roulette/types"
|
||||||
|
@ -13,7 +14,11 @@ import (
|
||||||
|
|
||||||
type Format struct{}
|
type Format struct{}
|
||||||
|
|
||||||
func (t Format) Css() string {
|
func (t Format) CSP(w http.ResponseWriter) string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Format) CSS() string {
|
||||||
var css strings.Builder
|
var css strings.Builder
|
||||||
|
|
||||||
css.WriteString(`html,body{margin:0;padding:0;height:100%;}`)
|
css.WriteString(`html,body{margin:0;padding:0;height:100%;}`)
|
||||||
|
@ -26,9 +31,10 @@ func (t Format) Title(rootUrl, fileUri, filePath, fileName, prefix, mime string)
|
||||||
return fmt.Sprintf(`<title>%s</title>`, fileName), nil
|
return fmt.Sprintf(`<title>%s</title>`, fileName), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Format) Body(rootUrl, fileUri, filePath, fileName, prefix, mime string) (string, error) {
|
func (t Format) Body(rootUrl, fileUri, filePath, fileName, prefix, mime, nonce string) (string, error) {
|
||||||
return fmt.Sprintf(`<a href="%s"><audio controls autoplay loop preload="auto"><source src="%s" type="%s" alt="Roulette selected: %s">Your browser does not support the audio tag.</audio></a>`,
|
return fmt.Sprintf(`<a href="%s"><audio nonce=%q controls autoplay loop preload="auto"><source src="%s" type="%s" alt="Roulette selected: %s">Your browser does not support the audio tag.</audio></a>`,
|
||||||
rootUrl,
|
rootUrl,
|
||||||
|
nonce,
|
||||||
fileUri,
|
fileUri,
|
||||||
mime,
|
mime,
|
||||||
fileName), nil
|
fileName), nil
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -24,7 +25,11 @@ type Format struct {
|
||||||
Theme string
|
Theme string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Format) Css() string {
|
func (t Format) CSP(w http.ResponseWriter) string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Format) CSS() string {
|
||||||
var css strings.Builder
|
var css strings.Builder
|
||||||
|
|
||||||
formatter := html.New(
|
formatter := html.New(
|
||||||
|
@ -68,7 +73,7 @@ func (t Format) Title(rootUrl, fileUri, filePath, fileName, prefix, mime string)
|
||||||
return fmt.Sprintf(`<title>%s</title>`, fileName), nil
|
return fmt.Sprintf(`<title>%s</title>`, fileName), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Format) Body(rootUrl, fileUri, filePath, fileName, prefix, mime string) (string, error) {
|
func (t Format) Body(rootUrl, fileUri, filePath, fileName, prefix, mime, nonce string) (string, error) {
|
||||||
contents, err := os.ReadFile(filePath)
|
contents, err := os.ReadFile(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
|
@ -6,6 +6,7 @@ package flash
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"seedno.de/seednode/roulette/types"
|
"seedno.de/seednode/roulette/types"
|
||||||
|
@ -13,7 +14,11 @@ import (
|
||||||
|
|
||||||
type Format struct{}
|
type Format struct{}
|
||||||
|
|
||||||
func (t Format) Css() string {
|
func (t Format) CSP(w http.ResponseWriter) string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Format) CSS() string {
|
||||||
var css strings.Builder
|
var css strings.Builder
|
||||||
|
|
||||||
css.WriteString(`html,body{margin:0;padding:0;height:100%;}`)
|
css.WriteString(`html,body{margin:0;padding:0;height:100%;}`)
|
||||||
|
@ -26,10 +31,10 @@ func (t Format) Title(rootUrl, fileUri, filePath, fileName, prefix, mime string)
|
||||||
return fmt.Sprintf(`<title>%s</title>`, fileName), nil
|
return fmt.Sprintf(`<title>%s</title>`, fileName), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Format) Body(rootUrl, fileUri, filePath, fileName, prefix, mime string) (string, error) {
|
func (t Format) Body(rootUrl, fileUri, filePath, fileName, prefix, mime, nonce string) (string, error) {
|
||||||
var html strings.Builder
|
var html strings.Builder
|
||||||
|
|
||||||
html.WriteString(fmt.Sprintf(`<script src="https://unpkg.com/@ruffle-rs/ruffle"></script><script>window.RufflePlayer.config = {autoplay:"on"};</script><embed src="%s"></embed>`, fileUri))
|
html.WriteString(fmt.Sprintf(`<script nonce=%q src="https://unpkg.com/@ruffle-rs/ruffle"></script><script>window.RufflePlayer.config = {autoplay:"on"};</script><embed src="%s"></embed>`, nonce, fileUri))
|
||||||
html.WriteString(fmt.Sprintf(`<br /><button onclick="window.location.href = '%s';">Next</button>`, rootUrl))
|
html.WriteString(fmt.Sprintf(`<br /><button onclick="window.location.href = '%s';">Next</button>`, rootUrl))
|
||||||
|
|
||||||
return html.String(), nil
|
return html.String(), nil
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
_ "image/jpeg"
|
_ "image/jpeg"
|
||||||
_ "image/png"
|
_ "image/png"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -30,7 +31,15 @@ type Format struct {
|
||||||
Fun bool
|
Fun bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Format) Css() string {
|
func (t Format) CSP(w http.ResponseWriter) string {
|
||||||
|
nonce := types.GetNonce(6)
|
||||||
|
|
||||||
|
w.Header().Add("Content-Security-Policy", fmt.Sprintf("default-src 'self' 'nonce-%s';", nonce))
|
||||||
|
|
||||||
|
return nonce
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Format) CSS() string {
|
||||||
var css strings.Builder
|
var css strings.Builder
|
||||||
|
|
||||||
css.WriteString(`html,body{margin:0;padding:0;height:100%;}`)
|
css.WriteString(`html,body{margin:0;padding:0;height:100%;}`)
|
||||||
|
@ -41,7 +50,7 @@ func (t Format) Css() string {
|
||||||
css.WriteString(`a{color:inherit;display:block;height:97%;width:100%;text-decoration:none;}`)
|
css.WriteString(`a{color:inherit;display:block;height:97%;width:100%;text-decoration:none;}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
css.WriteString(`img{margin:auto;display:block;max-width:97%;max-height:97%;`)
|
css.WriteString(`img{margin:auto;display:block;max-width:97%;max-height:97%;color:transparent;`)
|
||||||
css.WriteString(`object-fit:scale-down;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)`)
|
css.WriteString(`object-fit:scale-down;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)`)
|
||||||
if t.Fun {
|
if t.Fun {
|
||||||
rotate := rand.Intn(360)
|
rotate := rand.Intn(360)
|
||||||
|
@ -69,19 +78,26 @@ func (t Format) Title(rootUrl, fileUri, filePath, fileName, prefix, mime string)
|
||||||
dimensions.height), nil
|
dimensions.height), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Format) Body(rootUrl, fileUri, filePath, fileName, prefix, mime string) (string, error) {
|
func (t Format) Body(rootUrl, fileUri, filePath, fileName, prefix, mime, nonce string) (string, error) {
|
||||||
dimensions, err := ImageDimensions(filePath)
|
dimensions, err := ImageDimensions(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf(`<a href="%s"><img style="color: transparent;" onload="this.style.color='inherit'" onerror="this.style.color='inherit'" src="%s" width="%d" height="%d" type="%s" alt="Roulette selected: %s"></a>`,
|
var w strings.Builder
|
||||||
|
|
||||||
|
w.WriteString(fmt.Sprintf(`<a href="%s"><img nonce=%q id="main" src="%s" width="%d" height="%d" type="%s" alt="Roulette selected: %s"></a>`,
|
||||||
rootUrl,
|
rootUrl,
|
||||||
|
nonce,
|
||||||
fileUri,
|
fileUri,
|
||||||
dimensions.width,
|
dimensions.width,
|
||||||
dimensions.height,
|
dimensions.height,
|
||||||
mime,
|
mime,
|
||||||
fileName), nil
|
fileName))
|
||||||
|
|
||||||
|
w.WriteString(fmt.Sprintf(`<script nonce=%q>window.addEventListener("load", function (){ document.getElementById("main").style.color='inherit' });</script>`, nonce))
|
||||||
|
|
||||||
|
return w.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Format) Extensions() map[string]string {
|
func (t Format) Extensions() map[string]string {
|
||||||
|
|
|
@ -7,6 +7,7 @@ package text
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
@ -16,7 +17,11 @@ import (
|
||||||
|
|
||||||
type Format struct{}
|
type Format struct{}
|
||||||
|
|
||||||
func (t Format) Css() string {
|
func (t Format) CSP(w http.ResponseWriter) string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Format) CSS() string {
|
||||||
var css strings.Builder
|
var css strings.Builder
|
||||||
|
|
||||||
css.WriteString(`html,body{margin:0;padding:0;height:100%;}`)
|
css.WriteString(`html,body{margin:0;padding:0;height:100%;}`)
|
||||||
|
@ -31,7 +36,7 @@ func (t Format) Title(rootUrl, fileUri, filePath, fileName, prefix, mime string)
|
||||||
return fmt.Sprintf(`<title>%s</title>`, fileName), nil
|
return fmt.Sprintf(`<title>%s</title>`, fileName), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Format) Body(rootUrl, fileUri, filePath, fileName, prefix, mime string) (string, error) {
|
func (t Format) Body(rootUrl, fileUri, filePath, fileName, prefix, mime, nonce string) (string, error) {
|
||||||
body, err := os.ReadFile(filePath)
|
body, err := os.ReadFile(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
body = []byte{}
|
body = []byte{}
|
||||||
|
|
|
@ -5,6 +5,9 @@ Copyright © 2024 Seednode <seednode@seedno.de>
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -17,14 +20,17 @@ type Type interface {
|
||||||
// should be displayed inline (e.g. code) or embedded (e.g. images)
|
// should be displayed inline (e.g. code) or embedded (e.g. images)
|
||||||
Type() string
|
Type() string
|
||||||
|
|
||||||
|
// Adds a CSP header and returns a nonce to be used in generated pages
|
||||||
|
CSP(http.ResponseWriter) string
|
||||||
|
|
||||||
// Returns a CSS string used to format the corresponding page
|
// Returns a CSS string used to format the corresponding page
|
||||||
Css() string
|
CSS() string
|
||||||
|
|
||||||
// Returns an HTML <title> element for the specified file
|
// Returns an HTML <title> element for the specified file
|
||||||
Title(rootUrl, fileUri, filePath, fileName, prefix, mime string) (string, error)
|
Title(rootUrl, fileUri, filePath, fileName, prefix, mime string) (string, error)
|
||||||
|
|
||||||
// Returns an HTML <body> element used to display the specified file
|
// Returns an HTML <body> element used to display the specified file
|
||||||
Body(rootUrl, fileUri, filePath, fileName, prefix, mime string) (string, error)
|
Body(rootUrl, fileUri, filePath, fileName, prefix, mime, nonce string) (string, error)
|
||||||
|
|
||||||
// Returns a map of file extensions to MIME type strings.
|
// Returns a map of file extensions to MIME type strings.
|
||||||
Extensions() map[string]string
|
Extensions() map[string]string
|
||||||
|
@ -129,3 +135,11 @@ func removeDuplicateStr(strSlice []string) []string {
|
||||||
}
|
}
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetNonce(length int) string {
|
||||||
|
b := make([]byte, length)
|
||||||
|
if _, err := rand.Read(b); err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return hex.EncodeToString(b)
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ package video
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -14,7 +15,11 @@ import (
|
||||||
|
|
||||||
type Format struct{}
|
type Format struct{}
|
||||||
|
|
||||||
func (t Format) Css() string {
|
func (t Format) CSP(w http.ResponseWriter) string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Format) CSS() string {
|
||||||
var css strings.Builder
|
var css strings.Builder
|
||||||
|
|
||||||
css.WriteString(`html,body{margin:0;padding:0;height:100%;}`)
|
css.WriteString(`html,body{margin:0;padding:0;height:100%;}`)
|
||||||
|
@ -29,7 +34,7 @@ func (t Format) Title(rootUrl, fileUri, filePath, fileName, prefix, mime string)
|
||||||
return fmt.Sprintf(`<title>%s</title>`, fileName), nil
|
return fmt.Sprintf(`<title>%s</title>`, fileName), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Format) Body(rootUrl, fileUri, filePath, fileName, prefix, mime string) (string, error) {
|
func (t Format) Body(rootUrl, fileUri, filePath, fileName, prefix, mime, nonce string) (string, error) {
|
||||||
return fmt.Sprintf(`<a href="%s"><video controls autoplay loop preload="auto"><source src="%s" type="%s" alt="Roulette selected: %s">Your browser does not support the video tag.</video></a>`,
|
return fmt.Sprintf(`<a href="%s"><video controls autoplay loop preload="auto"><source src="%s" type="%s" alt="Roulette selected: %s">Your browser does not support the video tag.</video></a>`,
|
||||||
rootUrl,
|
rootUrl,
|
||||||
fileUri,
|
fileUri,
|
||||||
|
|
Loading…
Reference in New Issue