Add support for Content-Security-Policy in images
This commit adds support for the "Content-Security-Policy" header in the barrel images.
This commit is contained in:
parent
17d64826df
commit
760aae0dc1
32 changed files with 162 additions and 48 deletions
|
|
@ -15,6 +15,7 @@ var Provision wisski_distillery.Command = pv{}
|
|||
type pv struct {
|
||||
PHPVersion string `short:"p" long:"php" description:"specific php version to use for instance. Should be one of '8.0', '8.1'."`
|
||||
OPCacheDevelopment bool `short:"o" long:"opcache-devel" description:"Include opcache development configuration"`
|
||||
ContentSecurityPolicy string `short:"c" long:"content-security-policy" description:"Setup ContentSecurityPolicy"`
|
||||
Positionals struct {
|
||||
Slug string `positional-arg-name:"slug" required:"1-1" description:"slug of instance to create"`
|
||||
} `positional-args:"true"`
|
||||
|
|
@ -43,6 +44,7 @@ func (p pv) Run(context wisski_distillery.Context) error {
|
|||
System: models.System{
|
||||
PHP: p.PHPVersion,
|
||||
OpCacheDevelopment: p.OPCacheDevelopment,
|
||||
ContentSecurityPolicy: p.ContentSecurityPolicy,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ type rebuild struct {
|
|||
|
||||
PHPVersion string `short:"p" long:"php" description:"update to specific php version to use for instance. Should be one of '8.0', '8.1'."`
|
||||
OPCacheDevelopment bool `short:"o" long:"opcache-devel" description:"Include opcache development configuration"`
|
||||
ContentSecurityPolicy string `short:"c" long:"content-security-policy" description:"Setup ContentSecurityPolicy"`
|
||||
|
||||
Positionals struct {
|
||||
Slug []string `positional-arg-name:"SLUG" required:"0" description:"slug of instance or instances to run rebuild"`
|
||||
} `positional-args:"true"`
|
||||
|
|
@ -56,6 +58,7 @@ func (rb rebuild) Run(context wisski_distillery.Context) (err error) {
|
|||
return instance.SystemManager().Apply(context.Context, writer, models.System{
|
||||
PHP: rb.PHPVersion,
|
||||
OpCacheDevelopment: rb.OPCacheDevelopment,
|
||||
ContentSecurityPolicy: rb.ContentSecurityPolicy,
|
||||
}, true)
|
||||
}, wissKIs, status.SmartMessage(func(item *wisski.WissKI) string {
|
||||
return fmt.Sprintf("rebuild %q", item.Slug)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package cli
|
||||
|
||||
// ===========================================================================================================
|
||||
// This file was generated automatically at 13-07-2023 13:31:03 using gogenlicense.
|
||||
// This file was generated automatically at 13-07-2023 21:49:29 using gogenlicense.
|
||||
// Do not edit manually, as changes may be overwritten.
|
||||
// ===========================================================================================================
|
||||
|
||||
|
|
@ -4913,7 +4913,7 @@ package cli
|
|||
// # Generation
|
||||
//
|
||||
// This variable and the associated documentation have been automatically generated using the 'gogenlicense' tool.
|
||||
// It was last updated at 13-07-2023 13:31:03.
|
||||
// It was last updated at 13-07-2023 21:49:29.
|
||||
var LegalNotices string
|
||||
|
||||
func init() {
|
||||
|
|
|
|||
|
|
@ -120,6 +120,14 @@
|
|||
<code>{{ .Instance.System.OpCacheDevelopment }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Content Security Policy
|
||||
</td>
|
||||
<td>
|
||||
<code>{{ .Instance.System.ContentSecurityPolicy }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
|
@ -143,7 +151,7 @@
|
|||
Directory
|
||||
</td>
|
||||
<td>
|
||||
<code style="overflow: auto;">{{ .Instance.FilesystemBase }}</code>
|
||||
<code class="overflow">{{ .Instance.FilesystemBase }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
@ -351,7 +359,7 @@
|
|||
{{ $slug := .Instance.Slug }}
|
||||
{{ $csrf := .CSRF }}
|
||||
{{ range $index, $user := .Info.Users }}
|
||||
<tr {{ if not $user.Status }}style="color:gray" aria-disabled="true"{{ end }}>
|
||||
<tr {{ if not $user.Status }}class="disabled" aria-disabled="true"{{ end }}>
|
||||
<td>
|
||||
<code>{{ $user.UID }}</code>
|
||||
</td>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
<div class="pure-control-group">
|
||||
<label for="slug">Slug</label>
|
||||
<input name="slug" id="slug" placeholder="" autocomplete="slug">
|
||||
<input name="slug" id="slug" placeholder="">
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
|
|
@ -24,6 +24,10 @@
|
|||
<input type="checkbox" id="opcacheDevelopment" />
|
||||
Opache Development Configuration
|
||||
</label>
|
||||
<div class="pure-control-group">
|
||||
<label for="contentsecuritypolicy">Content Security Policy</label>
|
||||
<input class="pure-input-1" name="contentsecuritypolicy" id="contentsecuritypolicy" list="content-security-policy" placeholder="">
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Profile</legend>
|
||||
|
|
@ -36,3 +40,8 @@
|
|||
<input type="submit" value="Provision" class="pure-button">
|
||||
</form>
|
||||
</div>
|
||||
<datalist id="content-security-policy">
|
||||
{{ range .ContentSecurityPolicies }}
|
||||
<option value="{{ . }}">
|
||||
{{ end }}
|
||||
</datalist>
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
<div class="pure-u-1-1">
|
||||
<form class="pure-form pure-form-aligned" id="provision">
|
||||
<form class="pure-form pure-form-aligned" id="rebuild">
|
||||
<fieldset>
|
||||
<legend>Main Parameters</legend>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="slug">Slug</label>
|
||||
<input name="slug" id="slug" placeholder="" autocomplete="slug" readonly="readonly" value="{{ .Slug }}">
|
||||
<input name="slug" id="slug" placeholder="" readonly="readonly" value="{{ .Slug }}">
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
|
|
@ -22,9 +22,13 @@
|
|||
</select>
|
||||
</div>
|
||||
<label for="opcacheDevelopment" class="pure-checkbox">
|
||||
<input {{ if .System.OpCacheDevelopment }}checked{{end}} type="checkbox" id="opcacheDevelopment" check/>
|
||||
<input {{ if .System.OpCacheDevelopment }}checked{{end}} type="checkbox" id="opcacheDevelopment"/>
|
||||
Opache Development Configuration
|
||||
</label>
|
||||
<div class="pure-control-group" class="pure-input-1">
|
||||
<label for="contentsecuritypolicy">Content Security Policy</label>
|
||||
<input name="contentsecuritypolicy" id="contentsecuritypolicy" list="content-security-policy" value="{{ .System.ContentSecurityPolicy }}">
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Profile</legend>
|
||||
|
|
@ -37,3 +41,9 @@
|
|||
<input type="submit" value="Rebuild" class="pure-button">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<datalist id="content-security-policy">
|
||||
{{ range .ContentSecurityPolicies }}
|
||||
<option value="{{ . }}">
|
||||
{{ end }}
|
||||
</datalist>
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
<tbody>
|
||||
{{ $csrf := .CSRF }}
|
||||
{{ range .Users }}
|
||||
<tr {{ if not .User.IsEnabled }}style="color:gray"{{ end }}>
|
||||
<tr {{ if not .User.IsEnabled }}class="disabled"{{ end }}>
|
||||
<td>
|
||||
{{ .User.User }}
|
||||
</td>
|
||||
|
|
|
|||
|
|
@ -28,11 +28,13 @@ type instanceProvisionContext struct {
|
|||
|
||||
type systemParams struct {
|
||||
PHPVersions []string
|
||||
ContentSecurityPolicies []string
|
||||
DefaultPHPVersion string
|
||||
}
|
||||
|
||||
func newSystemParams() (sp systemParams) {
|
||||
sp.PHPVersions = models.KnownPHPVersions()
|
||||
sp.ContentSecurityPolicies = models.ContentSecurityPolicyExamples()
|
||||
sp.DefaultPHPVersion = models.DefaultPHPVersion
|
||||
return sp
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,17 +25,17 @@ var AssetsUser = Assets{
|
|||
// AssetsAdmin contains assets for the 'Admin' entrypoint.
|
||||
var AssetsAdmin = Assets{
|
||||
Scripts: `<script nomodule="" defer src="/⛰/User.e4c5f849.js"></script><script type="module" src="/⛰/User.fce9a3e3.js"></script><script type="module" src="/⛰/Default.38d394c2.js"></script><script src="/⛰/Default.38d394c2.js" nomodule="" defer></script><script type="module" src="/⛰/Admin.87f202f8.js"></script><script src="/⛰/Admin.1b10eebb.js" nomodule="" defer></script>`,
|
||||
Styles: `<link rel="stylesheet" href="/⛰/Default.938b4407.css"><link rel="stylesheet" href="/⛰/Admin.a1e05c23.css"><link rel="stylesheet" href="/⛰/User.840de3b4.css"><link rel="stylesheet" href="/⛰/User.68febbf8.css"><link rel="stylesheet" href="/⛰/Admin.d79c7b30.css">`,
|
||||
Styles: `<link rel="stylesheet" href="/⛰/Default.938b4407.css"><link rel="stylesheet" href="/⛰/Admin.a1e05c23.css"><link rel="stylesheet" href="/⛰/User.840de3b4.css"><link rel="stylesheet" href="/⛰/User.68febbf8.css"><link rel="stylesheet" href="/⛰/Admin.78d18bfa.css">`,
|
||||
}
|
||||
|
||||
// AssetsAdminProvision contains assets for the 'AdminProvision' entrypoint.
|
||||
var AssetsAdminProvision = Assets{
|
||||
Scripts: `<script nomodule="" defer src="/⛰/User.e4c5f849.js"></script><script nomodule="" defer src="/⛰/Admin.1b10eebb.js"></script><script type="module" src="/⛰/User.fce9a3e3.js"></script><script type="module" src="/⛰/Admin.87f202f8.js"></script><script type="module" src="/⛰/Default.38d394c2.js"></script><script src="/⛰/Default.38d394c2.js" nomodule="" defer></script><script type="module" src="/⛰/AdminProvision.9cbda41c.js"></script><script src="/⛰/AdminProvision.68dbff79.js" nomodule="" defer></script>`,
|
||||
Styles: `<link rel="stylesheet" href="/⛰/Default.938b4407.css"><link rel="stylesheet" href="/⛰/Admin.a1e05c23.css"><link rel="stylesheet" href="/⛰/User.840de3b4.css"><link rel="stylesheet" href="/⛰/User.68febbf8.css"><link rel="stylesheet" href="/⛰/Admin.d79c7b30.css"><link rel="stylesheet" href="/⛰/AdminProvision.38d394c2.css">`,
|
||||
Scripts: `<script nomodule="" defer src="/⛰/User.e4c5f849.js"></script><script nomodule="" defer src="/⛰/Admin.1b10eebb.js"></script><script type="module" src="/⛰/User.fce9a3e3.js"></script><script type="module" src="/⛰/Admin.87f202f8.js"></script><script type="module" src="/⛰/Default.38d394c2.js"></script><script src="/⛰/Default.38d394c2.js" nomodule="" defer></script><script type="module" src="/⛰/AdminProvision.d1b24c7b.js"></script><script src="/⛰/AdminProvision.0b361a8e.js" nomodule="" defer></script>`,
|
||||
Styles: `<link rel="stylesheet" href="/⛰/Default.938b4407.css"><link rel="stylesheet" href="/⛰/Admin.a1e05c23.css"><link rel="stylesheet" href="/⛰/User.840de3b4.css"><link rel="stylesheet" href="/⛰/User.68febbf8.css"><link rel="stylesheet" href="/⛰/Admin.78d18bfa.css"><link rel="stylesheet" href="/⛰/AdminProvision.38d394c2.css">`,
|
||||
}
|
||||
|
||||
// AssetsAdminRebuild contains assets for the 'AdminRebuild' entrypoint.
|
||||
var AssetsAdminRebuild = Assets{
|
||||
Scripts: `<script nomodule="" defer src="/⛰/User.e4c5f849.js"></script><script nomodule="" defer src="/⛰/Admin.1b10eebb.js"></script><script type="module" src="/⛰/User.fce9a3e3.js"></script><script type="module" src="/⛰/Admin.87f202f8.js"></script><script type="module" src="/⛰/Default.38d394c2.js"></script><script src="/⛰/Default.38d394c2.js" nomodule="" defer></script><script type="module" src="/⛰/AdminRebuild.0149f285.js"></script><script src="/⛰/AdminRebuild.6953ed8a.js" nomodule="" defer></script>`,
|
||||
Styles: `<link rel="stylesheet" href="/⛰/Default.938b4407.css"><link rel="stylesheet" href="/⛰/Admin.a1e05c23.css"><link rel="stylesheet" href="/⛰/User.840de3b4.css"><link rel="stylesheet" href="/⛰/User.68febbf8.css"><link rel="stylesheet" href="/⛰/Admin.d79c7b30.css"><link rel="stylesheet" href="/⛰/AdminRebuild.38d394c2.css">`,
|
||||
Scripts: `<script nomodule="" defer src="/⛰/User.e4c5f849.js"></script><script nomodule="" defer src="/⛰/Admin.1b10eebb.js"></script><script type="module" src="/⛰/User.fce9a3e3.js"></script><script type="module" src="/⛰/Admin.87f202f8.js"></script><script type="module" src="/⛰/Default.38d394c2.js"></script><script src="/⛰/Default.38d394c2.js" nomodule="" defer></script><script type="module" src="/⛰/AdminRebuild.6eda9153.js"></script><script src="/⛰/AdminRebuild.d9ab4bf2.js" nomodule="" defer></script>`,
|
||||
Styles: `<link rel="stylesheet" href="/⛰/Default.938b4407.css"><link rel="stylesheet" href="/⛰/Admin.a1e05c23.css"><link rel="stylesheet" href="/⛰/User.840de3b4.css"><link rel="stylesheet" href="/⛰/User.68febbf8.css"><link rel="stylesheet" href="/⛰/Admin.78d18bfa.css"><link rel="stylesheet" href="/⛰/AdminRebuild.38d394c2.css">`,
|
||||
}
|
||||
|
|
|
|||
1
internal/dis/component/server/assets/dist/Admin.78d18bfa.css
vendored
Normal file
1
internal/dis/component/server/assets/dist/Admin.78d18bfa.css
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.wisski{padding:1em}.wisski h3{padding:0}.wisski a.pure-button{float:right;position:relative;bottom:1em}.wisski.running{background-color:#9ada07}.wisski.stopped{background-color:#ff7a7a}.disabled{color:gray}.overflow{overflow:auto}.info-chip{min-width:75px;height:15px;text-align:center;border-radius:5px;padding:5px;display:block}.info-chip.note{color:#fff;background-color:gray}.info-chip.info{color:#fff;background-color:green}.info-chip.warning{color:#000;background-color:#ff0}.info-chip.error{color:#000;background-color:red}
|
||||
|
|
@ -1 +0,0 @@
|
|||
.wisski{padding:1em}.wisski h3{padding:0}.wisski a.pure-button{float:right;position:relative;bottom:1em}.wisski.running{background-color:#9ada07}.wisski.stopped{background-color:#ff7a7a}.info-chip{min-width:75px;height:15px;text-align:center;border-radius:5px;padding:5px;display:block}
|
||||
|
|
@ -1 +1 @@
|
|||
!function(){var e="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{},n={},t={},o=e.parcelRequireafa4;null==o&&((o=function(e){if(e in n)return n[e].exports;if(e in t){var o=t[e];delete t[e];var r={id:e,exports:{}};return n[e]=r,o.call(r.exports,r,r.exports),r.exports}var i=new Error("Cannot find module '"+e+"'");throw i.code="MODULE_NOT_FOUND",i}).register=function(e,n){t[e]=n},e.parcelRequireafa4=o),o("dK5Bi");var r,i=o("8vh0V");async function l(e){return await new Promise(((n,t)=>{(0,i.createModal)("provision",[JSON.stringify(e)],{bufferSize:0,onClose:(o,r)=>{o?n(e.Slug):t(new Error(null!=r?r:"unspecified error"))}})}))}const a=document.getElementById("provision"),d=document.getElementById("slug"),u=document.getElementById("php"),c=document.getElementById("opcacheDevelopment");a.addEventListener("submit",(e=>{e.preventDefault(),l({Slug:d.value,System:{PHP:u.value,OpCacheDevelopment:c.checked}}).then((e=>{location.href="/admin/instance/"+e})).catch((e=>{console.error(e),location.reload()}))})),null===(r=a.querySelector("fieldset"))||void 0===r||r.removeAttribute("disabled")}();
|
||||
!function(){var e="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{},n={},t={},o=e.parcelRequireafa4;null==o&&((o=function(e){if(e in n)return n[e].exports;if(e in t){var o=t[e];delete t[e];var r={id:e,exports:{}};return n[e]=r,o.call(r.exports,r,r.exports),r.exports}var i=new Error("Cannot find module '"+e+"'");throw i.code="MODULE_NOT_FOUND",i}).register=function(e,n){t[e]=n},e.parcelRequireafa4=o),o("dK5Bi");var r,i=o("8vh0V");async function l(e){return await new Promise(((n,t)=>{(0,i.createModal)("provision",[JSON.stringify(e)],{bufferSize:0,onClose:(o,r)=>{o?n(e.Slug):t(new Error(null!=r?r:"unspecified error"))}})}))}const d=document.getElementById("provision"),a=document.getElementById("slug"),u=document.getElementById("php"),c=document.getElementById("opcacheDevelopment"),s=document.getElementById("contentsecuritypolicy");d.addEventListener("submit",(e=>{e.preventDefault(),l({Slug:a.value,System:{PHP:u.value,OpCacheDevelopment:c.checked,ContentSecurityPolicy:s.value}}).then((e=>{location.href="/admin/instance/"+e})).catch((e=>{console.error(e),location.reload()}))})),null===(r=d.querySelector("fieldset"))||void 0===r||r.removeAttribute("disabled")}();
|
||||
|
|
@ -1 +0,0 @@
|
|||
var e="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{},n={},t={},o=e.parcelRequireafa4;null==o&&((o=function(e){if(e in n)return n[e].exports;if(e in t){var o=t[e];delete t[e];var r={id:e,exports:{}};return n[e]=r,o.call(r.exports,r,r.exports),r.exports}var i=new Error("Cannot find module '"+e+"'");throw i.code="MODULE_NOT_FOUND",i}).register=function(e,n){t[e]=n},e.parcelRequireafa4=o),o("8xGhL");var r=o("12vpF");async function i(e){return await new Promise(((n,t)=>{(0,r.createModal)("provision",[JSON.stringify(e)],{bufferSize:0,onClose:(o,r)=>{o?n(e.Slug):t(new Error(r??"unspecified error"))}})}))}const l=document.getElementById("provision"),a=document.getElementById("slug"),d=document.getElementById("php"),u=document.getElementById("opcacheDevelopment");l.addEventListener("submit",(e=>{e.preventDefault(),i({Slug:a.value,System:{PHP:d.value,OpCacheDevelopment:u.checked}}).then((e=>{location.href="/admin/instance/"+e})).catch((e=>{console.error(e),location.reload()}))})),l.querySelector("fieldset")?.removeAttribute("disabled");
|
||||
1
internal/dis/component/server/assets/dist/AdminProvision.d1b24c7b.js
vendored
Normal file
1
internal/dis/component/server/assets/dist/AdminProvision.d1b24c7b.js
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
var e="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{},t={},n={},o=e.parcelRequireafa4;null==o&&((o=function(e){if(e in t)return t[e].exports;if(e in n){var o=n[e];delete n[e];var r={id:e,exports:{}};return t[e]=r,o.call(r.exports,r,r.exports),r.exports}var i=new Error("Cannot find module '"+e+"'");throw i.code="MODULE_NOT_FOUND",i}).register=function(e,t){n[e]=t},e.parcelRequireafa4=o),o("8xGhL");var r=o("12vpF");async function i(e){return await new Promise(((t,n)=>{(0,r.createModal)("provision",[JSON.stringify(e)],{bufferSize:0,onClose:(o,r)=>{o?t(e.Slug):n(new Error(r??"unspecified error"))}})}))}const l=document.getElementById("provision"),a=document.getElementById("slug"),d=document.getElementById("php"),c=document.getElementById("opcacheDevelopment"),u=document.getElementById("contentsecuritypolicy");l.addEventListener("submit",(e=>{e.preventDefault(),i({Slug:a.value,System:{PHP:d.value,OpCacheDevelopment:c.checked,ContentSecurityPolicy:u.value}}).then((e=>{location.href="/admin/instance/"+e})).catch((e=>{console.error(e),location.reload()}))})),l.querySelector("fieldset")?.removeAttribute("disabled");
|
||||
|
|
@ -1 +0,0 @@
|
|||
var e="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{},n={},t={},o=e.parcelRequireafa4;null==o&&((o=function(e){if(e in n)return n[e].exports;if(e in t){var o=t[e];delete t[e];var r={id:e,exports:{}};return n[e]=r,o.call(r.exports,r,r.exports),r.exports}var i=new Error("Cannot find module '"+e+"'");throw i.code="MODULE_NOT_FOUND",i}).register=function(e,n){t[e]=n},e.parcelRequireafa4=o),o("8xGhL");var r=o("12vpF");async function i(e,n){return await new Promise(((t,o)=>{(0,r.createModal)("rebuild",[e,JSON.stringify(n)],{bufferSize:0,onClose:(n,r)=>{n?t(e):o(new Error(r??"unspecified error"))}})}))}const l=document.getElementById("slug"),a=document.getElementById("provision"),d=document.getElementById("php"),u=document.getElementById("opcacheDevelopment");a.addEventListener("submit",(e=>{e.preventDefault(),i(l.value,{PHP:d.value,OpCacheDevelopment:u.checked}).then((e=>{location.href="/admin/instance/"+e})).catch((e=>{console.error(e),location.reload()}))})),a.querySelector("fieldset")?.removeAttribute("disabled");
|
||||
|
|
@ -1 +0,0 @@
|
|||
!function(){var e="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{},n={},t={},o=e.parcelRequireafa4;null==o&&((o=function(e){if(e in n)return n[e].exports;if(e in t){var o=t[e];delete t[e];var r={id:e,exports:{}};return n[e]=r,o.call(r.exports,r,r.exports),r.exports}var i=new Error("Cannot find module '"+e+"'");throw i.code="MODULE_NOT_FOUND",i}).register=function(e,n){t[e]=n},e.parcelRequireafa4=o),o("dK5Bi");var r,i=o("8vh0V");async function l(e,n){return await new Promise(((t,o)=>{(0,i.createModal)("rebuild",[e,JSON.stringify(n)],{bufferSize:0,onClose:(n,r)=>{n?t(e):o(new Error(null!=r?r:"unspecified error"))}})}))}const d=document.getElementById("slug"),a=document.getElementById("provision"),u=document.getElementById("php"),c=document.getElementById("opcacheDevelopment");a.addEventListener("submit",(e=>{e.preventDefault(),l(d.value,{PHP:u.value,OpCacheDevelopment:c.checked}).then((e=>{location.href="/admin/instance/"+e})).catch((e=>{console.error(e),location.reload()}))})),null===(r=a.querySelector("fieldset"))||void 0===r||r.removeAttribute("disabled")}();
|
||||
1
internal/dis/component/server/assets/dist/AdminRebuild.6eda9153.js
vendored
Normal file
1
internal/dis/component/server/assets/dist/AdminRebuild.6eda9153.js
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
var e="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{},t={},n={},o=e.parcelRequireafa4;null==o&&((o=function(e){if(e in t)return t[e].exports;if(e in n){var o=n[e];delete n[e];var r={id:e,exports:{}};return t[e]=r,o.call(r.exports,r,r.exports),r.exports}var l=new Error("Cannot find module '"+e+"'");throw l.code="MODULE_NOT_FOUND",l}).register=function(e,t){n[e]=t},e.parcelRequireafa4=o),o("8xGhL");var r=o("12vpF");async function l(e,t){return await new Promise(((n,o)=>{(0,r.createModal)("rebuild",[e,JSON.stringify(t)],{bufferSize:0,onClose:(t,r)=>{t?n(e):o(new Error(r??"unspecified error"))}})}))}const i=document.getElementById("rebuild"),d=document.getElementById("slug"),a=document.getElementById("php"),c=document.getElementById("opcacheDevelopment"),u=document.getElementById("contentsecuritypolicy");i.addEventListener("submit",(e=>{e.preventDefault(),l(d.value,{PHP:a.value,OpCacheDevelopment:c.checked,ContentSecurityPolicy:u.value}).then((e=>{location.href="/admin/instance/"+e})).catch((e=>{console.error(e),location.reload()}))})),i.querySelector("fieldset")?.removeAttribute("disabled");
|
||||
1
internal/dis/component/server/assets/dist/AdminRebuild.d9ab4bf2.js
vendored
Normal file
1
internal/dis/component/server/assets/dist/AdminRebuild.d9ab4bf2.js
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
!function(){var e="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{},n={},t={},o=e.parcelRequireafa4;null==o&&((o=function(e){if(e in n)return n[e].exports;if(e in t){var o=t[e];delete t[e];var r={id:e,exports:{}};return n[e]=r,o.call(r.exports,r,r.exports),r.exports}var l=new Error("Cannot find module '"+e+"'");throw l.code="MODULE_NOT_FOUND",l}).register=function(e,n){t[e]=n},e.parcelRequireafa4=o),o("dK5Bi");var r,l=o("8vh0V");async function i(e,n){return await new Promise(((t,o)=>{(0,l.createModal)("rebuild",[e,JSON.stringify(n)],{bufferSize:0,onClose:(n,r)=>{n?t(e):o(new Error(null!=r?r:"unspecified error"))}})}))}const d=document.getElementById("rebuild"),a=document.getElementById("slug"),u=document.getElementById("php"),c=document.getElementById("opcacheDevelopment"),f=document.getElementById("contentsecuritypolicy");d.addEventListener("submit",(e=>{e.preventDefault(),i(a.value,{PHP:u.value,OpCacheDevelopment:c.checked,ContentSecurityPolicy:f.value}).then((e=>{location.href="/admin/instance/"+e})).catch((e=>{console.error(e),location.reload()}))})),null===(r=d.querySelector("fieldset"))||void 0===r||r.removeAttribute("disabled")}();
|
||||
|
|
@ -12,6 +12,8 @@
|
|||
bottom: 1em;
|
||||
}
|
||||
|
||||
/* WissKI Status */
|
||||
|
||||
.wisski.running {
|
||||
background-color: #9ADA07;
|
||||
}
|
||||
|
|
@ -20,6 +22,16 @@
|
|||
background-color: #ff7a7a;
|
||||
}
|
||||
|
||||
.disabled {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.overflow {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/* Informational Chips */
|
||||
|
||||
.info-chip {
|
||||
min-width: 75px;
|
||||
height: 15px;
|
||||
|
|
@ -28,3 +40,23 @@
|
|||
padding: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.info-chip.note {
|
||||
background-color: gray;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.info-chip.info {
|
||||
background-color: green;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.info-chip.warning {
|
||||
background-color: yellow;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.info-chip.error {
|
||||
background-color: red;
|
||||
color: #000;
|
||||
}
|
||||
|
|
@ -7,12 +7,13 @@ const provision = document.getElementById('provision') as HTMLFormElement
|
|||
const slug = document.getElementById('slug') as HTMLInputElement
|
||||
const php = document.getElementById('php') as HTMLSelectElement
|
||||
const opcacheDevelopment = document.getElementById('opcacheDevelopment') as HTMLInputElement
|
||||
const contentSecurityPolicy = document.getElementById('contentsecuritypolicy') as HTMLInputElement
|
||||
|
||||
// add an event handler to open the modal form!
|
||||
provision.addEventListener('submit', (evt) => {
|
||||
evt.preventDefault()
|
||||
|
||||
Provision({ Slug: slug.value, System: { PHP: php.value, OpCacheDevelopment: opcacheDevelopment.checked } })
|
||||
Provision({ Slug: slug.value, System: { PHP: php.value, OpCacheDevelopment: opcacheDevelopment.checked, ContentSecurityPolicy: contentSecurityPolicy.value } })
|
||||
.then(slug => {
|
||||
location.href = '/admin/instance/' + slug
|
||||
})
|
||||
|
|
|
|||
|
|
@ -3,16 +3,17 @@ import '../Admin/index.css'
|
|||
|
||||
import { Rebuild } from '~/src/lib/remote/api'
|
||||
|
||||
const rebuild = document.getElementById('rebuild') as HTMLFormElement
|
||||
const slug = document.getElementById('slug') as HTMLInputElement
|
||||
const provision = document.getElementById('provision') as HTMLFormElement
|
||||
const php = document.getElementById('php') as HTMLSelectElement
|
||||
const opcacheDevelopment = document.getElementById('opcacheDevelopment') as HTMLInputElement
|
||||
const contentSecurityPolicy = document.getElementById('contentsecuritypolicy') as HTMLInputElement
|
||||
|
||||
// add an event handler to open the modal form!
|
||||
provision.addEventListener('submit', (evt) => {
|
||||
rebuild.addEventListener('submit', (evt) => {
|
||||
evt.preventDefault()
|
||||
|
||||
Rebuild(slug.value, { PHP: php.value, OpCacheDevelopment: opcacheDevelopment.checked })
|
||||
Rebuild(slug.value, { PHP: php.value, OpCacheDevelopment: opcacheDevelopment.checked, ContentSecurityPolicy: contentSecurityPolicy.value })
|
||||
.then(slug => {
|
||||
location.href = '/admin/instance/' + slug
|
||||
})
|
||||
|
|
@ -20,4 +21,4 @@ provision.addEventListener('submit', (evt) => {
|
|||
})
|
||||
|
||||
// enable the form!
|
||||
provision.querySelector('fieldset')?.removeAttribute('disabled')
|
||||
rebuild.querySelector('fieldset')?.removeAttribute('disabled')
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ interface ProvisionFlags {
|
|||
interface System {
|
||||
PHP: string
|
||||
OpCacheDevelopment: boolean
|
||||
ContentSecurityPolicy: string
|
||||
}
|
||||
|
||||
/** Rebuild the specified instance */
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/models"
|
||||
"github.com/tkw1536/pkglib/contextx"
|
||||
"github.com/tkw1536/pkglib/httpx"
|
||||
"github.com/tkw1536/pkglib/mux"
|
||||
|
|
@ -107,6 +108,11 @@ func (server *Server) Server(ctx context.Context, progress io.Writer) (public ht
|
|||
// apply the given context function
|
||||
public = httpx.WithContextWrapper(&publicM, func(rcontext context.Context) context.Context { return contextx.WithValuesOf(rcontext, ctx) })
|
||||
internal = httpx.WithContextWrapper(&internalM, func(rcontext context.Context) context.Context { return contextx.WithValuesOf(rcontext, ctx) })
|
||||
|
||||
// Add Content-Security-Policy
|
||||
public = WithCSP(public, models.ContentSecurityPolicyDistilery)
|
||||
internal = WithCSP(internal, models.ContentSecurityPolicyNothing)
|
||||
|
||||
err = nil
|
||||
return
|
||||
}
|
||||
|
|
@ -123,6 +129,17 @@ func (server *Server) csrf() func(http.Handler) http.Handler {
|
|||
return csrf.Protect(server.Config.CSRFSecret(), opts...)
|
||||
}
|
||||
|
||||
// WithCSP adds a Content-Security-Policy header to every response
|
||||
func WithCSP(handler http.Handler, policy string) http.Handler {
|
||||
if policy == "" {
|
||||
return handler
|
||||
}
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Security-Policy", policy)
|
||||
handler.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func init() {
|
||||
httpx.InterceptorOnFallback = func(req *http.Request, err error) {
|
||||
zerolog.Ctx(req.Context()).Err(err).Msg("unknown error intercepted")
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ package models
|
|||
// It is embedded into the instances struct by gorm.
|
||||
type System struct {
|
||||
// NOTE(twiesing): Any changes here should be reflected in instance_{provision,rebuild}.html and remote/api.ts.
|
||||
PHP string `gorm:"column:php;not null"`
|
||||
OpCacheDevelopment bool `gorm:"column:opcache_devel;not null"`
|
||||
PHP string `gorm:"column:php;not null"` // php version to use
|
||||
OpCacheDevelopment bool `gorm:"column:opcache_devel;not null"` // opcache development
|
||||
|
||||
ContentSecurityPolicy string `gorm:"column:csp;not null"` // content security policy for the system
|
||||
}
|
||||
|
||||
const (
|
||||
|
|
@ -48,3 +50,17 @@ func (system System) GetDockerBaseImage() string {
|
|||
}
|
||||
return imagePrefix + version + imageSuffix
|
||||
}
|
||||
|
||||
const (
|
||||
// Content Security Policy used by the internal server
|
||||
ContentSecurityPolicyNothing = "base-uri 'self'; default-src 'none';"
|
||||
|
||||
// Content Security policy used by the distillery admin server
|
||||
ContentSecurityPolicyDistilery = "base-uri 'self'; default-src 'self'; img-src 'self' data:; media-src 'none'; worker-src 'none'; frame-src 'none'; frame-ancestors 'none';"
|
||||
)
|
||||
|
||||
func ContentSecurityPolicyExamples() []string {
|
||||
return []string{
|
||||
ContentSecurityPolicyDistilery,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,13 +59,13 @@ type Requirement struct {
|
|||
func (req Requirement) Level() template.HTML {
|
||||
switch req.Severity {
|
||||
case -1:
|
||||
return "<span style='background-color: gray; color: #fff;' class='info-chip'>Note</span>"
|
||||
return "<span class='info-chip note'>Note</span>"
|
||||
case 0:
|
||||
return "<span style='background-color: green; color: #fff;' class='info-chip'>Info</span>"
|
||||
return "<span class='info-chip info'>Info</span>"
|
||||
case 1:
|
||||
return "<span style='background-color: yellow; color: #000;' class='info-chip'>Warning</span>"
|
||||
return "<span class='info-chip warning'>Warning</span>"
|
||||
case 2:
|
||||
return "<span style='background-color: red; color: #000;' class='info-chip'>Error</span>"
|
||||
return "<span class='info-chip error'>Error</span>"
|
||||
}
|
||||
return template.HTML(strconv.Itoa(req.Severity))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
|
||||
# allow the following files:
|
||||
!conf/*
|
||||
!apache.d/*
|
||||
!scripts/*
|
||||
!ssh/*
|
||||
!php.ini.d/*
|
||||
|
|
@ -76,7 +76,7 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
|
|||
docker-php-source delete
|
||||
|
||||
# enable the apache rewrite mod
|
||||
RUN a2enmod rewrite
|
||||
RUN a2enmod rewrite headers
|
||||
|
||||
|
||||
# Install composer.
|
||||
|
|
@ -94,6 +94,8 @@ ADD php.ini.d/wisski.ini /usr/local/etc/php/conf.d/wisski.ini
|
|||
ARG OPCACHE_MODE=prod
|
||||
ADD php.ini.d/opcache-$OPCACHE_MODE.ini /usr/local/etc/php/conf.d/opcache.ini
|
||||
|
||||
ARG CONTENT_SECURITY_POLICY=
|
||||
ENV CONTENT_SECURITY_POLICY=${CONTENT_SECURITY_POLICY}
|
||||
|
||||
# Configure Apache.
|
||||
|
||||
|
|
@ -102,8 +104,8 @@ RUN rm /etc/apache2/sites-available/*.conf && \
|
|||
rm /etc/apache2/sites-enabled/*.conf
|
||||
|
||||
# Then add the WissKI site
|
||||
ADD conf/ports.conf /etc/apache2/ports.conf
|
||||
ADD conf/wisski.conf /etc/apache2/sites-available/wisski.conf
|
||||
ADD apache.d/conf/ports.conf /etc/apache2/ports.conf
|
||||
ADD apache.d/sites-available/wisski.conf /etc/apache2/sites-available/wisski.conf
|
||||
|
||||
# And enable it
|
||||
RUN a2ensite wisski
|
||||
|
|
|
|||
|
|
@ -19,6 +19,11 @@
|
|||
Require all granted
|
||||
</Directory>
|
||||
|
||||
# Read the CONTENT_SECURITY_POLICY from the environment!
|
||||
PassEnv CONTENT_SECURITY_POLICY
|
||||
Header set Content-Security-Policy %{CONTENT_SECURITY_POLICY}e "expr=-n osenv('CONTENT_SECURITY_POLICY')"
|
||||
|
||||
# Don't low to allow ignoring everything
|
||||
ErrorLog /dev/stderr
|
||||
CustomLog /dev/stdout combined
|
||||
</VirtualHost>
|
||||
|
|
@ -7,6 +7,8 @@ services:
|
|||
args:
|
||||
BARREL_BASE_IMAGE: ${BARREL_BASE_IMAGE}
|
||||
OPCACHE_MODE: ${OPCACHE_MODE}
|
||||
CONTENT_SECURITY_POLICY: ${CONTENT_SECURITY_POLICY}
|
||||
|
||||
logging:
|
||||
driver: none
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ func (barrel *Barrel) Stack() component.StackWithResources {
|
|||
|
||||
"BARREL_BASE_IMAGE": barrel.GetDockerBaseImage(),
|
||||
"OPCACHE_MODE": barrel.OpCacheMode(),
|
||||
"CONTENT_SECURITY_POLICY": barrel.ContentSecurityPolicy,
|
||||
},
|
||||
|
||||
MakeDirs: []string{"data", ".composer"},
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ func (smanager *SystemManager) Apply(ctx context.Context, progress io.Writer, sy
|
|||
return err
|
||||
}
|
||||
|
||||
// TODO: Apply Content-Security-Policy!
|
||||
|
||||
// and rebuild
|
||||
return smanager.Dependencies.Barrel.Build(ctx, progress, start)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue