Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions data/serverHeaders/dynamic/Content-Security-Policy.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"delimiter" = "; "
"subDelimiter" = " "

[subFields]
"default-src" = "'self'"
"manifest-src" = "'self'"

"connect-src" = [
"'self'",
"##VAR_analytics##"
]

"font-src" = ""

"img-src" = [
"'self'",
"data:"
]

"script-src" = [
"'self'",
"##VAR_analytics##",
"'##VAR_scriptHashes##'"
]

"style-src" = [
"'self'",
"'##VAR_styleHashes##'"
]
15 changes: 15 additions & 0 deletions data/serverHeaders/static.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Strict-Transport-Security = "max-age=31536000; includeSubDomains"
X-Content-Type-Options = "nosniff"
X-Frame-Options = "SAMEORIGIN"
Referrer-Policy = "strict-origin"
Permissions-Policy = [
"geolocation=(self)",
"microphone=()",
"camera=()"
]
Access-Control-Allow-Origin = "*"
X-XSS-Protection = "1; mode=block"
Cache-Control = [
"public",
"max-age=31536000"
]
3 changes: 3 additions & 0 deletions layouts/_partials/collect-headers.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{{- $dynamicHeaders := partial "head/dynamic-headers.html" . }}
{{- $headers := merge site.Data.serverHeaders.static $dynamicHeaders }}
{{- return $headers -}}
62 changes: 62 additions & 0 deletions layouts/_partials/collect-redirects.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{{- $ctx := . }}
{{- $curPage := .Page }}
{{- $redirects := dict }}
{{- $domainRedirectValues := dict }}
{{- with site.Data.serverRedirects.domains.redirectDomains }}
{{- range . }}
{{- $srcValue := printf "http://%s/*" . }}
{{- $redirValue := printf "%s://%s/:splat" (or site.Data.serverRedirects.domains.targetScheme "https") site.Data.serverRedirects.domains.targetDomain }}
{{- $domainRedirectValues = merge $domainRedirectValues (dict
$srcValue $redirValue
) }}
{{- end }}
{{- end }}
{{- if ne (or site.Data.serverRedirects.domains.targetScheme "https") "http" }}
{{- $srcValue := printf "http://%s/*" site.Data.serverRedirects.domains.targetDomain }}
{{- $redirValue := printf "%s://%s/:splat" (or site.Data.serverRedirects.domains.targetScheme "https") site.Data.serverRedirects.domains.targetDomain }}
{{- $domainRedirectValues = merge $domainRedirectValues (dict
$srcValue $redirValue
) }}
{{- end }}
{{- $hard301 := (dict "301!" $domainRedirectValues )}}
{{- $redirects = merge $redirects $hard301 }}
{{- $aliasRedirects := dict }}
{{- with site.Pages }}
{{- range . }}
{{- if .Aliases }}
{{- $rTarget := .RelPermalink }}
{{- range .Aliases }}
{{- $srcValue := . }}
{{- $aliasRedirects = merge $aliasRedirects (dict
$srcValue $rTarget
) }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
{{- $hard301 := (dict "301!" $aliasRedirects )}}
{{- $redirects = merge $redirects $hard301 }}
{{- $regularRedirects := dict }}
{{- $extraRedirects := dict }}
{{- with (index site.Data.serverRedirects "path-status") }}
{{- $extraRedirects = merge $extraRedirects . }}
{{- end }}
{{- with site.Data.serverRedirects.wildcard }}
{{- $extraRedirects = merge $extraRedirects . }}
{{- end }}
{{- with $extraRedirects }}
{{- range $status, $redirects := . }}
{{- range $redirects }}
{{- $splitRedir := split . " " }}
{{- if eq (len $splitRedir) 2 }}
{{- $regularRedirects = merge $regularRedirects (dict
$status (dict (index $splitRedir 0) (index $splitRedir 1))
) }}
{{- else }}
{{- errorf "Redirect '%s' invalid (wrong number of spaces)" . }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
{{- $redirects = merge $redirects $regularRedirects }}
{{- return $redirects -}}
81 changes: 81 additions & 0 deletions layouts/_partials/footer/esbuild-hash.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{{- /* ESBUILD-HASH.HTML - Build javascript modules with esbuild
* Simple Usage: {{ partial "esbuild" "js/file.js" }}
* Simple Usage: {{ partial "esbuild" (dict "src" "js/file.js" "load" "defer/async" "babel" true ) }}
* Parameters:
* src - javascript file to build, relative to assets folder. Must include file extension can be .js or .ts
* load - can set to "defer" or "async" defaults to null.
* babel - set to true to transpile your js using babel. Note: all js is lowered to es6 by default.
* for babel you must have the required babel dependencies installed , and configured
* see hugo babel doc https://gohugo.io/hugo-pipes/babel
* use the babel option if esbuild can't handle lowering your es6+ code, or you wish to go lower than es6
* for unsupported es6+ syntax see
* https://esbuild.github.io/content-types/#javascript
*
* example for checking hugo env from js file
*
* import * as params from '@params';
*
* if (params.env === 'development') {
* console.log('hugo deveolopment environment')
* } else {
* console.log('hugo production environment')
* }
*
* ----------------------------------------------------------------*/ -}}
{{- /* get source from . or .src and fetch resource */ -}}
{{- $src := . -}}
{{- if not $src -}}
{{- errorf `You must provide a source as the partial context, or (dict .src "path")` -}}
{{- end -}}
{{- /* set .load only if valid option provided in dict */ -}}
{{- $load := "" -}}
{{- /* set .babel only if provided in dict */ -}}
{{- $babel := false -}}
{{- /* check for dict */ -}}
{{- if reflect.IsMap . -}}
{{- with .src -}}
{{- $src = . -}}
{{- else -}}
{{- errorf "as you are providing params as a dict, you must provide the source file as .src" -}}
{{- end -}}
{{- with .load -}}
{{- $loadOpts := slice "async" "defer" -}}
{{- if not (in $loadOpts . ) -}}
{{- errorf "Invalid .load %q for file /assets/%s - valid options are %s." . $src (delimit $loadOpts ", " " and " ) -}}
{{- end -}}
{{- $load = . }}
{{- end -}}
{{- with .babel -}}
{{- if eq . true -}}
{{- $babel = true -}}
{{- else -}}
{{- errorf "Invalid .babel option of %q. The only valid option is true" . -}}
{{- end -}}
{{- end -}}
{{ end }}
{{- /* get the resource from .src path */ -}}
{{- $resource := resources.Get $src -}}
{{- /* if resources.Get fails */ -}}
{{- if not $resource }}
{{- errorf "No js resource found at /assets/%s" $src -}}
{{- end -}}
{{- /* pass hugo env to the js file as a param */ -}}
{{- $params := (dict "env" hugo.Environment) -}}
{{- /* standard production configuration for es build */ -}}
{{- $jsConfig := (dict "target" "es2015" "minify" "true" "params" $params) }}
{{- $js := $resource | js.Build $jsConfig | fingerprint -}}
{{- /* is .babelEs6 is set to true - use babel to lower to es6 */ -}}
{{- if $babel -}}
{{- $babelConfig := (dict "noComments" true "minified" true "config" "config/babel.module.config.js") -}}
{{- $js = $resource| js.Build $jsConfig | babel $babelConfig | fingerprint -}}
{{- end -}}
{{- if eq (hugo.Environment) "development" -}}
{{- $jsConfig = (dict "sourceMap" "inline" "target" "es2015" "params" $params) -}}
{{- $js = $resource | js.Build $jsConfig | fingerprint -}}
{{- end -}}
{{- return (dict
"src" $src
"js" $js
"load" $load
"hash" $js.Data.Integrity
) -}}
87 changes: 9 additions & 78 deletions layouts/_partials/footer/esbuild.html
Original file line number Diff line number Diff line change
@@ -1,79 +1,10 @@
{{- /* ESBUILD.HTML - Build javascript modules with esbuild
* Simple Usage: {{ partial "esbuild" "js/file.js" }}
* Simple Usage: {{ partial "esbuild" (dict "src" "js/file.js" "load" "defer/async" "babel" true ) }}
* Parameters:
* src - javascript file to build, relative to assets folder. Must include file extension can be .js or .ts
* load - can set to "defer" or "async" defaults to null.
* babel - set to true to transpile your js using babel. Note: all js is lowered to es6 by default.
* for babel you must have the required babel dependencies installed , and configured
* see hugo babel doc https://gohugo.io/hugo-pipes/babel
* use the babel option if esbuild can't handle lowering your es6+ code, or you wish to go lower than es6
* for unsupported es6+ syntax see
* https://esbuild.github.io/content-types/#javascript
*
* example for checking hugo env from js file
*
* import * as params from '@params';
*
* if (params.env === 'development') {
* console.log('hugo deveolopment environment')
* } else {
* console.log('hugo production environment')
* }
*
* ----------------------------------------------------------------*/ -}}
{{- /* get source from . or .src and fetch resource */ -}}
{{- $src := . -}}
{{- if not $src -}}
{{- errorf `You must provide a source as the partial context, or (dict .src "path")` -}}
{{- end -}}
{{- /* set .load only if valid option provided in dict */ -}}
{{- $load := "" -}}
{{- /* set .babel only if provided in dict */ -}}
{{- $babel := false -}}
{{- /* check for dict */ -}}
{{- if reflect.IsMap . -}}
{{- with .src -}}
{{- $src = . -}}
{{- else -}}
{{- errorf "as you are providing params as a dict, you must provide the source file as .src" -}}
{{- end -}}
{{- with .load -}}
{{- $loadOpts := slice "async" "defer" -}}
{{- if not (in $loadOpts . ) -}}
{{- errorf "Invalid .load %q for file /assets/%s - valid options are %s." . $src (delimit $loadOpts ", " " and " ) -}}
{{- end -}}
{{- $load = . }}
{{- end -}}
{{- with .babel -}}
{{- if eq . true -}}
{{- $babel = true -}}
{{- else -}}
{{- errorf "Invalid .babel option of %q. The only valid option is true" . -}}
{{- end -}}
{{- end -}}
{{ end }}
{{- /* get the resource from .src path */ -}}
{{- $resource := resources.Get $src -}}
{{- /* if resources.Get fails */ -}}
{{- if not $resource }}
{{- errorf "No js resource found at /assets/%s" $src -}}
{{- end -}}
{{- /* pass hugo env to the js file as a param */ -}}
{{- $params := (dict "env" hugo.Environment) -}}
{{- /* standard production configuration for es build */ -}}
{{- $jsConfig := (dict "target" "es2015" "minify" "true" "params" $params) }}
{{- $js := $resource | js.Build $jsConfig | fingerprint -}}
{{- /* is .babelEs6 is set to true - use babel to lower to es6 */ -}}
{{- if $babel -}}
{{- $babelConfig := (dict "noComments" true "minified" true "config" "config/babel.module.config.js") -}}
{{- $js = $resource| js.Build $jsConfig | babel $babelConfig | fingerprint -}}
{{- end -}}
{{- if eq (hugo.Environment) "development" -}}
{{- $jsConfig = (dict "sourceMap" "inline" "target" "es2015" "params" $params) -}}
{{- $js = $resource | js.Build $jsConfig | fingerprint -}}
{{- /* Call out to ESBILD-HASH.HTML to generate JS and calculate hash
* We do it this way so the hash can be available for adding to the
* Content-Security-Policy headers
*/ -}}
{{- $scriptHash := partial "footer/esbuild-hash.html" . }}
{{- with $scriptHash }}
<script {{ with $scriptHash.load }}{{ . | safeHTMLAttr }}{{ end }}
src="{{- $scriptHash.js.RelPermalink -}}"
integrity="{{- $scriptHash.js.Data.Integrity -}}"></script>
{{ end -}}

<script {{ with $load }}{{ . | safeHTMLAttr }}{{ end }}
src="{{- $js.RelPermalink -}}"
integrity="{{- $js.Data.Integrity -}}"></script>
80 changes: 80 additions & 0 deletions layouts/_partials/head/dynamic-headers.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
{{- $curPage := .Page }}
{{- $headersDict := dict }}
{{- range $header, $valueMap := site.Data.serverHeaders.dynamic }}
{{- $valueString := "" }}
{{- if not (reflect.IsMap $valueMap) }}
{{- errorf "Dynamic header '%s' is not a map in 'data'" $header }}
{{- end }}
{{- $delimiter := $valueMap.delimiter }}
{{- $subDelimiter := $valueMap.subDelimiter }}
{{- if reflect.IsMap $valueMap.subFields }}
{{- $fieldDelim := "" }}
{{- range $field, $value := $valueMap.subFields }}
{{- $subFieldNewValue := "" }}
{{- if reflect.IsSlice $value }}
{{- $subFieldNewValue = partial "buildSubField.html" (dict
"Page" $curPage
"subFieldName" $field
"subFieldOldValue" $subFieldNewValue
"subFieldNewValue" (index $value 0)
"valueDelim" ""
) }}
{{- range after 1 $value }}
{{- $subFieldNewValue = partial "buildSubField.html" (dict
"Page" $curPage
"subFieldName" $field
"subFieldOldValue" $subFieldNewValue
"subFieldNewValue" .
"valueDelim" $subDelimiter
) }}
{{- end }}
{{- else }}
{{- $subFieldNewValue = partial "buildSubField.html" (dict
"Page" $curPage
"subFieldName" $field
"subFieldNewValue" $value
"subFieldOldValue" ""
"valueDelim" ""
) }}
{{- end }}
{{- if $subFieldNewValue }}
{{- $valueString = (add $valueString $fieldDelim $field " " $subFieldNewValue) }}
{{- end }}
{{- if not $fieldDelim }}
{{- $fieldDelim = $delimiter }}
{{- end }}
{{- end }}
{{- else }}
{{- errorf "Dynamic header '%s' missing subFields map" $header }}
{{- end }}
{{- $headersDict = merge $headersDict (dict $header $valueString) }}
{{- end }}
{{- return $headersDict -}}

{{ define "_partials/buildSubField.html" }}
{{- $curPage := .Page }}
{{- $subField := .subFieldName }}
{{- $value := .subFieldNewValue }}
{{- $oldValue := .subFieldOldValue }}
{{- $valueDelim := .valueDelim }}
{{- $newValue := "" }}
{{- $customVar := findRESubmatch `^["']?##VAR_([0-9a-zA-Z-]+)##['"]?$` $value }}
{{- $customQuotes := findRESubmatch `^(["'])?##VAR_[0-9a-zA-Z-]+##['"]?$` $value }}
{{- if and $customVar (index (index $customVar 0) 1) }}
{{- $customVar = (index (index $customVar 0) 1) }}
{{- if templates.Exists (printf "_partials/head/header-custom-values/var-%s.html" $customVar) }}
{{- $customValue := partial (printf "head/header-custom-values/var-%s.html" $customVar) $curPage }}
{{- if reflect.IsSlice $customValue }}
{{- if and $customQuotes (index (index $customQuotes 0) 1) }}
{{- $customQuotes = index (index $customQuotes 0) 1 }}
{{- $customValue = add $customQuotes (delimit $customValue (add $customQuotes $valueDelim $customQuotes)) $customQuotes }}
{{- else }}
{{- $customValue = delimit $customValue $valueDelim }}
{{- end }}
{{- end }}
{{- $value = $customValue }}
{{- end }}
{{- end }}
{{- $newValue = (add $oldValue $valueDelim $value) }}
{{- return $newValue }}
{{ end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{- with site.Params.analyticsUrl }}{{- . -}}{{- end -}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{{- $scriptHashes := slice }}
{{- $footerScriptHash := partial "footer/esbuild" (dict "src" "js/app.js" "targetPath" "main.js" "load" "async" "transpile" false) -}}
{{- with $footerScriptHash }}
{{- with .hash }}
{{- $scriptHashes = $scriptHashes | append . }}
{{- end }}
{{- end -}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{{- $styleHashes := (union
((partial "head/stylesheet-hashes.html" .).hashes)
((partial "head/libsass-hash.html" "scss/app.scss").hashes)
) -}}
{{- return $styleHashes -}}
12 changes: 12 additions & 0 deletions layouts/_partials/head/libsass-hash.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{{- $css := "" -}}
{{- if eq (hugo.Environment) "development" -}}
{{- $options := (dict "targetPath" "main.css" "transpiler" "libsass" "enableSourceMap" true "includePaths" (slice "node_modules")) -}}
{{- $css = resources.Get . | toCSS $options | resources.Fingerprint "sha512" -}}
{{- else -}}
{{- $options := (dict "targetPath" "main.css" "transpiler" "libsass" "outputStyle" "compressed" "includePaths" (slice "node_modules")) -}}
{{- $css = resources.Get . | toCSS $options | postCSS (dict "config" "config/postcss.config.js") | resources.Fingerprint "sha512" | resources.PostProcess -}}
{{- end -}}
{{- return (dict
"cssSrc" (slice $css)
"hashes" (slice $css.Data.Integrity)
) -}}
Loading