wip allow for more cdns
add res template function add ExtraCSPOrigins config setting add StaticResBase config setting skip flush directives
This commit is contained in:
parent
d4fd85f75c
commit
43d72e6f3b
|
@ -10,6 +10,7 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"mime"
|
"mime"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -23,12 +24,14 @@ import (
|
||||||
//type SFileList map[string]*SFile
|
//type SFileList map[string]*SFile
|
||||||
//type SFileListShort map[string]*SFile
|
//type SFileListShort map[string]*SFile
|
||||||
|
|
||||||
var StaticFiles = SFileList{make(map[string]*SFile),make(map[string]*SFile)}
|
var StaticFiles = SFileList{"/s/", make(map[string]*SFile), make(map[string]*SFile)}
|
||||||
|
|
||||||
//var StaticFilesShort SFileList = make(map[string]*SFile)
|
//var StaticFilesShort SFileList = make(map[string]*SFile)
|
||||||
var staticFileMutex sync.RWMutex
|
var staticFileMutex sync.RWMutex
|
||||||
|
|
||||||
// ? Is it efficient to have two maps for this?
|
// ? Is it efficient to have two maps for this?
|
||||||
type SFileList struct {
|
type SFileList struct {
|
||||||
|
Prefix string
|
||||||
Long map[string]*SFile
|
Long map[string]*SFile
|
||||||
Short map[string]*SFile
|
Short map[string]*SFile
|
||||||
}
|
}
|
||||||
|
@ -305,7 +308,7 @@ func (l SFileList) JSTmplInit() error {
|
||||||
hasher.Write(data)
|
hasher.Write(data)
|
||||||
checksum := hex.EncodeToString(hasher.Sum(nil))
|
checksum := hex.EncodeToString(hasher.Sum(nil))
|
||||||
|
|
||||||
l.Set("/s/"+path, &SFile{data, gzipData, brData, checksum, path + "?h=" + checksum, 0, int64(len(data)), strconv.Itoa(len(data)), int64(len(gzipData)), strconv.Itoa(len(gzipData)), int64(len(brData)), strconv.Itoa(len(brData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)})
|
l.Set(l.Prefix+path, &SFile{data, gzipData, brData, checksum, l.Prefix + path + "?h=" + checksum, 0, int64(len(data)), strconv.Itoa(len(data)), int64(len(gzipData)), strconv.Itoa(len(gzipData)), int64(len(brData)), strconv.Itoa(len(brData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)})
|
||||||
|
|
||||||
DebugLogf("Added the '%s' static file.", path)
|
DebugLogf("Added the '%s' static file.", path)
|
||||||
return nil
|
return nil
|
||||||
|
@ -367,7 +370,7 @@ func (l SFileList) Init() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
l.Set("/s/"+path, &SFile{data, gzipData, brData, checksum, path + "?h=" + checksum, 0, int64(len(data)), strconv.Itoa(len(data)), int64(len(gzipData)), strconv.Itoa(len(gzipData)), int64(len(brData)), strconv.Itoa(len(brData)), mimetype, f, f.ModTime().UTC().Format(http.TimeFormat)})
|
l.Set(l.Prefix+path, &SFile{data, gzipData, brData, checksum, l.Prefix + path + "?h=" + checksum, 0, int64(len(data)), strconv.Itoa(len(data)), int64(len(gzipData)), strconv.Itoa(len(gzipData)), int64(len(brData)), strconv.Itoa(len(brData)), mimetype, f, f.ModTime().UTC().Format(http.TimeFormat)})
|
||||||
|
|
||||||
DebugLogf("Added the '%s' static file.", path)
|
DebugLogf("Added the '%s' static file.", path)
|
||||||
return nil
|
return nil
|
||||||
|
@ -424,7 +427,7 @@ func (l SFileList) Add(path, prefix string) error {
|
||||||
hasher.Write(data)
|
hasher.Write(data)
|
||||||
checksum := hex.EncodeToString(hasher.Sum(nil))
|
checksum := hex.EncodeToString(hasher.Sum(nil))
|
||||||
|
|
||||||
l.Set("/s/"+path, &SFile{data, gzipData, brData, checksum, path + "?h=" + checksum, 0, int64(len(data)), strconv.Itoa(len(data)), int64(len(gzipData)), strconv.Itoa(len(gzipData)), int64(len(brData)), strconv.Itoa(len(brData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)})
|
l.Set(l.Prefix+path, &SFile{data, gzipData, brData, checksum, l.Prefix + path + "?h=" + checksum, 0, int64(len(data)), strconv.Itoa(len(data)), int64(len(gzipData)), strconv.Itoa(len(gzipData)), int64(len(brData)), strconv.Itoa(len(brData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)})
|
||||||
|
|
||||||
DebugLogf("Added the '%s' static file", path)
|
DebugLogf("Added the '%s' static file", path)
|
||||||
return nil
|
return nil
|
||||||
|
@ -448,8 +451,13 @@ func (l SFileList) GetShort(name string) (file *SFile, exists bool) {
|
||||||
func (l SFileList) Set(name string, data *SFile) {
|
func (l SFileList) Set(name string, data *SFile) {
|
||||||
staticFileMutex.Lock()
|
staticFileMutex.Lock()
|
||||||
defer staticFileMutex.Unlock()
|
defer staticFileMutex.Unlock()
|
||||||
l.Long[name] = data
|
// TODO: Propagate errors back up
|
||||||
l.Short[strings.TrimPrefix("/s/",name)] = data
|
uurl, err := url.Parse(name)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
l.Long[uurl.Path] = data
|
||||||
|
l.Short[strings.TrimPrefix(strings.TrimPrefix(name, l.Prefix), "/")] = data
|
||||||
}
|
}
|
||||||
|
|
||||||
var gzipBestCompress sync.Pool
|
var gzipBestCompress sync.Pool
|
||||||
|
|
|
@ -2,11 +2,13 @@ package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Site holds the basic settings which should be tweaked when setting up a site, we might move them to the settings table at some point
|
// Site holds the basic settings which should be tweaked when setting up a site, we might move them to the settings table at some point
|
||||||
|
@ -119,6 +121,9 @@ type config struct {
|
||||||
RefNoRef bool
|
RefNoRef bool
|
||||||
NoEmbed bool
|
NoEmbed bool
|
||||||
|
|
||||||
|
ExtraCSPOrigins string
|
||||||
|
StaticResBase string // /s/
|
||||||
|
|
||||||
Noavatar string // ? - Move this into the settings table?
|
Noavatar string // ? - Move this into the settings table?
|
||||||
ItemsPerPage int // ? - Move this into the settings table?
|
ItemsPerPage int // ? - Move this into the settings table?
|
||||||
MaxTopicTitleLength int
|
MaxTopicTitleLength int
|
||||||
|
@ -238,6 +243,21 @@ func ProcessConfig() (err error) {
|
||||||
}
|
}
|
||||||
Site.MaxRequestSize = Config.MaxRequestSize
|
Site.MaxRequestSize = Config.MaxRequestSize
|
||||||
|
|
||||||
|
local := func(h string) bool {
|
||||||
|
return h == "localhost" || h == "127.0.0.1" || h == "::1" || h == Site.URL
|
||||||
|
}
|
||||||
|
uurl, err := url.Parse(Config.StaticResBase)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to parse Config.StaticResBase: ")
|
||||||
|
}
|
||||||
|
host := uurl.Hostname()
|
||||||
|
if !local(host) {
|
||||||
|
Config.ExtraCSPOrigins += " " + host
|
||||||
|
}
|
||||||
|
if Config.StaticResBase != "" {
|
||||||
|
StaticFiles.Prefix = Config.StaticResBase
|
||||||
|
}
|
||||||
|
|
||||||
if Config.PostIPCutoff == 0 {
|
if Config.PostIPCutoff == 0 {
|
||||||
Config.PostIPCutoff = 120 // Default cutoff
|
Config.PostIPCutoff = 120 // Default cutoff
|
||||||
}
|
}
|
||||||
|
|
|
@ -878,6 +878,17 @@ func initDefaultTmplFuncMap() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmap["res"] = func(nameInt interface{}) interface{} {
|
||||||
|
n := nameInt.(string)
|
||||||
|
if n[0] == '/' && n[1] == '/' {
|
||||||
|
} else {
|
||||||
|
if f, ok := StaticFiles.GetShort(n); ok {
|
||||||
|
n = f.OName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
DefaultTemplateFuncMap = fmap
|
DefaultTemplateFuncMap = fmap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -119,6 +119,7 @@ func NewCTemplateSet(in string) *CTemplateSet {
|
||||||
"js": true,
|
"js": true,
|
||||||
"index": true,
|
"index": true,
|
||||||
"flush": true,
|
"flush": true,
|
||||||
|
"res": true,
|
||||||
},
|
},
|
||||||
logger: log.New(f, "", log.LstdFlags),
|
logger: log.New(f, "", log.LstdFlags),
|
||||||
loggerf: f,
|
loggerf: f,
|
||||||
|
@ -683,8 +684,9 @@ func (c *CTemplateSet) compileSwitch(con CContext, node parse.Node) {
|
||||||
for _, cmd := range node.Pipe.Cmds {
|
for _, cmd := range node.Pipe.Cmds {
|
||||||
c.detail("If Node Bit:", cmd)
|
c.detail("If Node Bit:", cmd)
|
||||||
c.detail("Bit Type:", reflect.ValueOf(cmd).Type().Name())
|
c.detail("Bit Type:", reflect.ValueOf(cmd).Type().Name())
|
||||||
expr += c.compileExprSwitch(con, cmd)
|
exprStep := c.compileExprSwitch(con, cmd)
|
||||||
c.detail("Expression Step:", c.compileExprSwitch(con, cmd))
|
expr += exprStep
|
||||||
|
c.detail("Expression Step:", exprStep)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.detail("Expression:", expr)
|
c.detail("Expression:", expr)
|
||||||
|
@ -1031,8 +1033,7 @@ func (c *CTemplateSet) compileExprSwitch(con CContext, node *parse.CommandNode)
|
||||||
case *parse.NilNode:
|
case *parse.NilNode:
|
||||||
panic("Nil is not a command x.x")
|
panic("Nil is not a command x.x")
|
||||||
case *parse.PipeNode:
|
case *parse.PipeNode:
|
||||||
c.detail("Pipe Node!")
|
c.detail("Pipe Node:", n)
|
||||||
c.detail(n)
|
|
||||||
c.detail("Node Args:", node.Args)
|
c.detail("Node Args:", node.Args)
|
||||||
out += c.compileIdentSwitchN(con, node)
|
out += c.compileIdentSwitchN(con, node)
|
||||||
default:
|
default:
|
||||||
|
@ -1043,9 +1044,9 @@ func (c *CTemplateSet) compileExprSwitch(con CContext, node *parse.CommandNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CTemplateSet) unknownNode(n parse.Node) {
|
func (c *CTemplateSet) unknownNode(n parse.Node) {
|
||||||
elem := reflect.ValueOf(n).Elem()
|
el := reflect.ValueOf(n).Elem()
|
||||||
c.logger.Println("Unknown Kind:", elem.Kind())
|
c.logger.Println("Unknown Kind:", el.Kind())
|
||||||
c.logger.Println("Unknown Type:", elem.Type().Name())
|
c.logger.Println("Unknown Type:", el.Type().Name())
|
||||||
panic("I don't know what node this is! Grr...")
|
panic("I don't know what node this is! Grr...")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1114,7 +1115,7 @@ func (c *CTemplateSet) compareJoin(con CContext, pos int, node *parse.CommandNod
|
||||||
return pos, out
|
return pos, out
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CTemplateSet) compileIdentSwitch(con CContext, node *parse.CommandNode) (out string, val reflect.Value, literal, notident bool) {
|
func (c *CTemplateSet) compileIdentSwitch(con CContext, node *parse.CommandNode) (out string, val reflect.Value, literal, notIdent bool) {
|
||||||
c.dumpCall("compileIdentSwitch", con, node)
|
c.dumpCall("compileIdentSwitch", con, node)
|
||||||
litString := func(inner string, bytes bool) {
|
litString := func(inner string, bytes bool) {
|
||||||
if !bytes {
|
if !bytes {
|
||||||
|
@ -1135,9 +1136,16 @@ ArgLoop:
|
||||||
var rout string
|
var rout string
|
||||||
pos, rout = c.compareJoin(con, pos, node, c.funcMap[id.String()].(string)) // TODO: Test this
|
pos, rout = c.compareJoin(con, pos, node, c.funcMap[id.String()].(string)) // TODO: Test this
|
||||||
out += rout
|
out += rout
|
||||||
case "le", "lt", "gt", "ge", "eq", "ne":
|
case "le", "lt", "gt", "ge":
|
||||||
out += c.compareFunc(con, pos, node, c.funcMap[id.String()].(string))
|
out += c.compareFunc(con, pos, node, c.funcMap[id.String()].(string))
|
||||||
break ArgLoop
|
break ArgLoop
|
||||||
|
case "eq", "ne":
|
||||||
|
o := c.compareFunc(con, pos, node, c.funcMap[id.String()].(string))
|
||||||
|
if out == "!" {
|
||||||
|
o = "(" + o + ")"
|
||||||
|
}
|
||||||
|
out += o
|
||||||
|
break ArgLoop
|
||||||
case "add", "subtract", "divide", "multiply":
|
case "add", "subtract", "divide", "multiply":
|
||||||
rout, rval := c.simpleMath(con, pos, node, c.funcMap[id.String()].(string))
|
rout, rval := c.simpleMath(con, pos, node, c.funcMap[id.String()].(string))
|
||||||
out += rout
|
out += rout
|
||||||
|
@ -1236,7 +1244,7 @@ ArgLoop:
|
||||||
// ! Slightly crude but it does the job
|
// ! Slightly crude but it does the job
|
||||||
leftParam := strings.Replace(leftOp, "\"", "", -1)
|
leftParam := strings.Replace(leftOp, "\"", "", -1)
|
||||||
c.langIndexToName = append(c.langIndexToName, leftParam)
|
c.langIndexToName = append(c.langIndexToName, leftParam)
|
||||||
notident = true
|
notIdent = true
|
||||||
con.PushPhrase(len(c.langIndexToName) - 1)
|
con.PushPhrase(len(c.langIndexToName) - 1)
|
||||||
} else {
|
} else {
|
||||||
leftParam := leftOp
|
leftParam := leftOp
|
||||||
|
@ -1386,17 +1394,37 @@ ArgLoop:
|
||||||
|
|
||||||
// TODO: Refactor this
|
// TODO: Refactor this
|
||||||
// TODO: Call the template function directly rather than going through RunThemeTemplate to eliminate a round of indirection?
|
// TODO: Call the template function directly rather than going through RunThemeTemplate to eliminate a round of indirection?
|
||||||
out = "{\nerr := " + headParam + ".Theme.RunTmpl(" + nameParam + "," + pageParam + ",w)\n"
|
out = "{\ne := " + headParam + ".Theme.RunTmpl(" + nameParam + "," + pageParam + ",w)\n"
|
||||||
out += "if err != nil {\nreturn err\n}\n}\n"
|
out += "if e != nil {\nreturn e\n}\n}\n"
|
||||||
literal = true
|
literal = true
|
||||||
break ArgLoop
|
break ArgLoop
|
||||||
case "flush":
|
case "flush":
|
||||||
if c.lang == "js" {
|
literal = true
|
||||||
|
break ArgLoop
|
||||||
|
/*if c.lang == "js" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
out = "if fl, ok := iw.(http.Flusher); ok {\nfl.Flush()\n}\n"
|
out = "if fl, ok := iw.(http.Flusher); ok {\nfl.Flush()\n}\n"
|
||||||
literal = true
|
literal = true
|
||||||
c.importMap["net/http"] = "net/http"
|
c.importMap["net/http"] = "net/http"
|
||||||
|
break ArgLoop*/
|
||||||
|
// TODO: Test this
|
||||||
|
case "res":
|
||||||
|
leftOp := node.Args[pos+1].String()
|
||||||
|
if len(leftOp) == 0 {
|
||||||
|
panic("The leftoperand for function res cannot be left blank")
|
||||||
|
}
|
||||||
|
leftParam, _ := c.compileIfVarSub(con, leftOp)
|
||||||
|
literal = true
|
||||||
|
if leftParam[0] == '"' {
|
||||||
|
if leftParam[1] == '/' && leftParam[2] == '/' {
|
||||||
|
litString(leftParam, false)
|
||||||
|
break ArgLoop
|
||||||
|
}
|
||||||
|
out = "{n := " + leftParam + "\nif f, ok := c.StaticFiles.GetShort(n); ok {\nw.Write(StringToBytes(f.OName))\n} else {\nw.Write(StringToBytes(n))\n}}\n"
|
||||||
|
break ArgLoop
|
||||||
|
}
|
||||||
|
out = "{n := " + leftParam + "\nif n[0] == '/' && n[1] == '/' {\n} else {\nif f, ok := c.StaticFiles.GetShort(n); ok {\nn = f.OName\n}\nw.Write(StringToBytes(n))\n}\n"
|
||||||
break ArgLoop
|
break ArgLoop
|
||||||
default:
|
default:
|
||||||
c.detail("Variable!")
|
c.detail("Variable!")
|
||||||
|
@ -1410,7 +1438,7 @@ ArgLoop:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.retCall("compileIdentSwitch", out, val, literal)
|
c.retCall("compileIdentSwitch", out, val, literal)
|
||||||
return out, val, literal, notident
|
return out, val, literal, notIdent
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CTemplateSet) compileReflectSwitch(con CContext, node *parse.CommandNode) (out string, outVal reflect.Value) {
|
func (c *CTemplateSet) compileReflectSwitch(con CContext, node *parse.CommandNode) (out string, outVal reflect.Value) {
|
||||||
|
|
|
@ -284,7 +284,7 @@ func (t *Theme) AddThemeStaticFiles() error {
|
||||||
hasher.Write(data)
|
hasher.Write(data)
|
||||||
checksum := hex.EncodeToString(hasher.Sum(nil))
|
checksum := hex.EncodeToString(hasher.Sum(nil))
|
||||||
|
|
||||||
StaticFiles.Set("/s/"+t.Name+path, &SFile{data, gzipData, brData, checksum, t.Name + path + "?h=" + checksum, 0, int64(len(data)), strconv.Itoa(len(data)), int64(len(gzipData)), strconv.Itoa(len(gzipData)), int64(len(brData)), strconv.Itoa(len(brData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)})
|
StaticFiles.Set(StaticFiles.Prefix+t.Name+path, &SFile{data, gzipData, brData, checksum, StaticFiles.Prefix + t.Name + path + "?h=" + checksum, 0, int64(len(data)), strconv.Itoa(len(data)), int64(len(gzipData)), strconv.Itoa(len(gzipData)), int64(len(brData)), strconv.Itoa(len(brData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)})
|
||||||
|
|
||||||
DebugLog("Added the '/" + t.Name + path + "' static file for theme " + t.Name + ".")
|
DebugLog("Added the '/" + t.Name + path + "' static file for theme " + t.Name + ".")
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -126,6 +126,10 @@ RefNoRef - This switch makes it so that if a user clicks on a link, then the inc
|
||||||
|
|
||||||
NoEmbed - Don't expand links into videos or images. Default: false
|
NoEmbed - Don't expand links into videos or images. Default: false
|
||||||
|
|
||||||
|
ExtraCSPOrigins - Extra origins which may want whitelisted in the default Content Security Policy.
|
||||||
|
|
||||||
|
StaticResBase - The default prefix for static resource files. May be a path or an external domain like a CDN domain. Default: /s/
|
||||||
|
|
||||||
NoAvatar - The default avatar to use for users when they don't have their own. The default for this may change in the near future to better utilise HTTP/2. Example: https://api.adorable.io/avatars/{width}/{id}.png
|
NoAvatar - The default avatar to use for users when they don't have their own. The default for this may change in the near future to better utilise HTTP/2. Example: https://api.adorable.io/avatars/{width}/{id}.png
|
||||||
|
|
||||||
ItemsPerPage - The number of posts, topics, etc. you want on each page.
|
ItemsPerPage - The number of posts, topics, etc. you want on each page.
|
||||||
|
|
|
@ -139,15 +139,15 @@ func FootHeaders(w http.ResponseWriter, h *c.Header) {
|
||||||
he := w.Header()
|
he := w.Header()
|
||||||
if c.Config.SslSchema {
|
if c.Config.SslSchema {
|
||||||
if h.ExternalMedia {
|
if h.ExternalMedia {
|
||||||
he.Set("Content-Security-Policy", "default-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-eval' 'unsafe-inline'; img-src * data: 'unsafe-eval' 'unsafe-inline'; connect-src * 'unsafe-eval' 'unsafe-inline'; frame-src 'self' www.youtube-nocookie.com embed.nicovideo.jp;upgrade-insecure-requests")
|
he.Set("Content-Security-Policy", "default-src 'self' 'unsafe-eval'"+c.Config.ExtraCSPOrigins+"; style-src 'self' 'unsafe-eval' 'unsafe-inline'; img-src * data: 'unsafe-eval' 'unsafe-inline'; connect-src * 'unsafe-eval' 'unsafe-inline'; frame-src 'self' www.youtube-nocookie.com embed.nicovideo.jp;upgrade-insecure-requests")
|
||||||
} else {
|
} else {
|
||||||
he.Set("Content-Security-Policy", "default-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-eval' 'unsafe-inline'; img-src * data: 'unsafe-eval' 'unsafe-inline'; connect-src * 'unsafe-eval' 'unsafe-inline'; frame-src 'self';upgrade-insecure-requests")
|
he.Set("Content-Security-Policy", "default-src 'self' 'unsafe-eval'"+c.Config.ExtraCSPOrigins+"; style-src 'self' 'unsafe-eval' 'unsafe-inline'; img-src * data: 'unsafe-eval' 'unsafe-inline'; connect-src * 'unsafe-eval' 'unsafe-inline'; frame-src 'self';upgrade-insecure-requests")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if h.ExternalMedia {
|
if h.ExternalMedia {
|
||||||
he.Set("Content-Security-Policy", "default-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-eval' 'unsafe-inline'; img-src * data: 'unsafe-eval' 'unsafe-inline'; connect-src * 'unsafe-eval' 'unsafe-inline'; frame-src 'self' www.youtube-nocookie.com embed.nicovideo.jp")
|
he.Set("Content-Security-Policy", "default-src 'self' 'unsafe-eval'"+c.Config.ExtraCSPOrigins+"; style-src 'self' 'unsafe-eval' 'unsafe-inline'; img-src * data: 'unsafe-eval' 'unsafe-inline'; connect-src * 'unsafe-eval' 'unsafe-inline'; frame-src 'self' www.youtube-nocookie.com embed.nicovideo.jp")
|
||||||
} else {
|
} else {
|
||||||
he.Set("Content-Security-Policy", "default-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-eval' 'unsafe-inline'; img-src * data: 'unsafe-eval' 'unsafe-inline'; connect-src * 'unsafe-eval' 'unsafe-inline'; frame-src 'self'")
|
he.Set("Content-Security-Policy", "default-src 'self' 'unsafe-eval'"+c.Config.ExtraCSPOrigins+"; style-src 'self' 'unsafe-eval' 'unsafe-inline'; img-src * data: 'unsafe-eval' 'unsafe-inline'; connect-src * 'unsafe-eval' 'unsafe-inline'; frame-src 'self'")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,16 +3,16 @@
|
||||||
<head>
|
<head>
|
||||||
<title>{{.Title}} | {{.Header.Site.Name}}</title>
|
<title>{{.Title}} | {{.Header.Site.Name}}</title>
|
||||||
{{range .Header.Stylesheets}}
|
{{range .Header.Stylesheets}}
|
||||||
<link href="/s/{{.}}"rel="stylesheet"type="text/css">{{end}}
|
<link href="{{.}}"rel="stylesheet"type="text/css">{{end}}
|
||||||
{{range .Header.PreScriptsAsync}}
|
{{range .Header.PreScriptsAsync}}
|
||||||
<script async src="/s/{{.}}"></script>{{end}}
|
<script async src="{{.}}"></script>{{end}}
|
||||||
{{if .CurrentUser.Loggedin}}<meta property="x-mem"content="1">{{end}}
|
{{if .CurrentUser.Loggedin}}<meta property="x-mem"content="1">{{end}}
|
||||||
<script src="/s/init.js?i=12"></script>
|
<script src="{{res "init.js"}}"></script>
|
||||||
{{range .Header.ScriptsAsync}}
|
{{range .Header.ScriptsAsync}}
|
||||||
<script async src="/s/{{.}}"></script>{{end}}
|
<script async src="{{.}}"></script>{{end}}
|
||||||
<script src="/s/jquery-3.1.1.min.js"></script>
|
<script src="{{res "jquery-3.1.1.min.js"}}"></script>
|
||||||
{{range .Header.Scripts}}
|
{{range .Header.Scripts}}
|
||||||
<script src="/s/{{.}}"></script>{{end}}
|
<script src="{{.}}"></script>{{end}}
|
||||||
<meta name="viewport"content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
|
<meta name="viewport"content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
|
||||||
{{if .Header.MetaDesc}}<meta name="description"content="{{.Header.MetaDesc}}">{{end}}
|
{{if .Header.MetaDesc}}<meta name="description"content="{{.Header.MetaDesc}}">{{end}}
|
||||||
{{/** TODO: Have page / forum / topic level tags and descriptions below as-well **/}}
|
{{/** TODO: Have page / forum / topic level tags and descriptions below as-well **/}}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<main id="topicPage">
|
<main id="topicPage">
|
||||||
|
|
||||||
{{if gt .Page 1}}<link rel="prev"href="{{.Topic.Link}}?page={{subtract .Page 1}}"/>{{end}}
|
{{if gt .Page 1}}<link rel="prev"href="{{.Topic.Link}}?page={{subtract .Page 1}}">{{end}}
|
||||||
{{if ne .LastPage .Page}}<link rel="prerender next"href="{{.Topic.Link}}?page={{add .Page 1}}"/>{{end}}
|
{{if ne .LastPage .Page}}<link rel="prerender next"href="{{.Topic.Link}}?page={{add .Page 1}}">{{end}}
|
||||||
{{if not .CurrentUser.Loggedin}}<link rel="canonical" href="//{{.Site.URL}}{{.Topic.Link}}{{if gt .Page 1}}?page={{.Page}}{{end}}"/>{{end}}
|
{{if not .CurrentUser.Loggedin}}<link rel="canonical"href="//{{.Site.URL}}{{.Topic.Link}}{{if gt .Page 1}}?page={{.Page}}{{end}}">{{end}}
|
||||||
|
|
||||||
<div {{scope "topic_title_block"}} class="rowblock rowhead topic_block"aria-label="{{lang "topic.topic_info_aria"}}">
|
<div {{scope "topic_title_block"}} class="rowblock rowhead topic_block"aria-label="{{lang "topic.topic_info_aria"}}">
|
||||||
<div class="rowitem topic_item{{if .Topic.Sticky}} topic_sticky_head{{else if .Topic.IsClosed}} topic_closed_head{{end}}">
|
<div class="rowitem topic_item{{if .Topic.Sticky}} topic_sticky_head{{else if .Topic.IsClosed}} topic_closed_head{{end}}">
|
||||||
|
|
Loading…
Reference in New Issue