mirror of
https://github.com/drakkan/sftpgo.git
synced 2024-11-25 00:50:31 +00:00
httpd: allow to configure cache control header
Some checks failed
Code scanning - action / CodeQL-Build (push) Has been cancelled
CI / Test and deploy (1.22, macos-latest, true) (push) Has been cancelled
CI / Test and deploy (1.22, ubuntu-latest, true) (push) Has been cancelled
CI / Test and deploy (1.22, windows-latest, false) (push) Has been cancelled
CI / Test build flags (push) Has been cancelled
CI / Test with PgSQL/MySQL/Cockroach (push) Has been cancelled
CI / Build Linux packages (aarch64, ubuntu18.04, latest, arm64) (push) Has been cancelled
CI / Build Linux packages (amd64, ubuntu:18.04, latest, amd64) (push) Has been cancelled
CI / Build Linux packages (armv7, ubuntu18.04, latest, arm7) (push) Has been cancelled
CI / Build Linux packages (ppc64le, ubuntu18.04, latest, ppc64le) (push) Has been cancelled
CI / golangci-lint (push) Has been cancelled
Docker / Build (alpine, false, ubuntu-latest) (push) Has been cancelled
Docker / Build (alpine, true, ubuntu-latest) (push) Has been cancelled
Docker / Build (debian, false, ubuntu-latest) (push) Has been cancelled
Docker / Build (debian, true, ubuntu-latest) (push) Has been cancelled
Docker / Build (debian-plugins, true, ubuntu-latest) (push) Has been cancelled
Docker / Build (distroless, false, ubuntu-latest) (push) Has been cancelled
Some checks failed
Code scanning - action / CodeQL-Build (push) Has been cancelled
CI / Test and deploy (1.22, macos-latest, true) (push) Has been cancelled
CI / Test and deploy (1.22, ubuntu-latest, true) (push) Has been cancelled
CI / Test and deploy (1.22, windows-latest, false) (push) Has been cancelled
CI / Test build flags (push) Has been cancelled
CI / Test with PgSQL/MySQL/Cockroach (push) Has been cancelled
CI / Build Linux packages (aarch64, ubuntu18.04, latest, arm64) (push) Has been cancelled
CI / Build Linux packages (amd64, ubuntu:18.04, latest, amd64) (push) Has been cancelled
CI / Build Linux packages (armv7, ubuntu18.04, latest, arm7) (push) Has been cancelled
CI / Build Linux packages (ppc64le, ubuntu18.04, latest, ppc64le) (push) Has been cancelled
CI / golangci-lint (push) Has been cancelled
Docker / Build (alpine, false, ubuntu-latest) (push) Has been cancelled
Docker / Build (alpine, true, ubuntu-latest) (push) Has been cancelled
Docker / Build (debian, false, ubuntu-latest) (push) Has been cancelled
Docker / Build (debian, true, ubuntu-latest) (push) Has been cancelled
Docker / Build (debian-plugins, true, ubuntu-latest) (push) Has been cancelled
Docker / Build (distroless, false, ubuntu-latest) (push) Has been cancelled
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
parent
2cc2fc64db
commit
6f8bc59756
8 changed files with 40 additions and 3 deletions
|
@ -144,6 +144,7 @@ var (
|
|||
ContentSecurityPolicy: "",
|
||||
PermissionsPolicy: "",
|
||||
CrossOriginOpenerPolicy: "",
|
||||
CacheControl: "",
|
||||
},
|
||||
Branding: httpd.Branding{},
|
||||
}
|
||||
|
@ -1547,6 +1548,12 @@ func getHTTPDSecurityConfFromEnv(idx int) (httpd.SecurityConf, bool) { //nolint:
|
|||
isSet = true
|
||||
}
|
||||
|
||||
cacheControl, ok := os.LookupEnv(fmt.Sprintf("SFTPGO_HTTPD__BINDINGS__%v__SECURITY__CACHE_CONTROL", idx))
|
||||
if ok {
|
||||
result.CacheControl = cacheControl
|
||||
isSet = true
|
||||
}
|
||||
|
||||
return result, isSet
|
||||
}
|
||||
|
||||
|
|
|
@ -1203,6 +1203,7 @@ func TestHTTPDBindingsFromEnv(t *testing.T) {
|
|||
os.Setenv("SFTPGO_HTTPD__BINDINGS__2__SECURITY__CONTENT_SECURITY_POLICY", "script-src $NONCE")
|
||||
os.Setenv("SFTPGO_HTTPD__BINDINGS__2__SECURITY__PERMISSIONS_POLICY", "fullscreen=(), geolocation=()")
|
||||
os.Setenv("SFTPGO_HTTPD__BINDINGS__2__SECURITY__CROSS_ORIGIN_OPENER_POLICY", "same-origin")
|
||||
os.Setenv("SFTPGO_HTTPD__BINDINGS__2__SECURITY__CACHE_CONTROL", "private")
|
||||
os.Setenv("SFTPGO_HTTPD__BINDINGS__2__EXTRA_CSS__0__PATH", "path1")
|
||||
os.Setenv("SFTPGO_HTTPD__BINDINGS__2__EXTRA_CSS__1__PATH", "path2")
|
||||
os.Setenv("SFTPGO_HTTPD__BINDINGS__2__BRANDING__WEB_ADMIN__FAVICON_PATH", "favicon.ico")
|
||||
|
@ -1267,6 +1268,7 @@ func TestHTTPDBindingsFromEnv(t *testing.T) {
|
|||
os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__SECURITY__CONTENT_SECURITY_POLICY")
|
||||
os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__SECURITY__PERMISSIONS_POLICY")
|
||||
os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__SECURITY__CROSS_ORIGIN_OPENER_POLICY")
|
||||
os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__SECURITY__CACHE_CONTROL")
|
||||
os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__EXTRA_CSS__0__PATH")
|
||||
os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__EXTRA_CSS__1__PATH")
|
||||
os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__BRANDING__WEB_ADMIN__FAVICON_PATH")
|
||||
|
@ -1376,6 +1378,7 @@ func TestHTTPDBindingsFromEnv(t *testing.T) {
|
|||
require.Equal(t, "script-src $NONCE", bindings[2].Security.ContentSecurityPolicy)
|
||||
require.Equal(t, "fullscreen=(), geolocation=()", bindings[2].Security.PermissionsPolicy)
|
||||
require.Equal(t, "same-origin", bindings[2].Security.CrossOriginOpenerPolicy)
|
||||
require.Equal(t, "private", bindings[2].Security.CacheControl)
|
||||
require.Equal(t, "favicon.ico", bindings[2].Branding.WebAdmin.FaviconPath)
|
||||
require.Equal(t, "logo.png", bindings[2].Branding.WebClient.LogoPath)
|
||||
require.Equal(t, "disclaimer", bindings[2].Branding.WebClient.DisclaimerName)
|
||||
|
|
|
@ -342,7 +342,9 @@ type SecurityConf struct {
|
|||
PermissionsPolicy string `json:"permissions_policy" mapstructure:"permissions_policy"`
|
||||
// CrossOriginOpenerPolicy allows to set the `Cross-Origin-Opener-Policy` header value. Default is "".
|
||||
CrossOriginOpenerPolicy string `json:"cross_origin_opener_policy" mapstructure:"cross_origin_opener_policy"`
|
||||
proxyHeaders []string
|
||||
// CacheControl allow to set the Cache-Control header value.
|
||||
CacheControl string `json:"cache_control" mapstructure:"cache_control"`
|
||||
proxyHeaders []string
|
||||
}
|
||||
|
||||
func (s *SecurityConf) updateProxyHeaders() {
|
||||
|
|
|
@ -414,6 +414,7 @@ func TestMain(m *testing.M) {
|
|||
Value: "https",
|
||||
},
|
||||
},
|
||||
CacheControl: "private",
|
||||
}
|
||||
httpdtest.SetBaseURL(httpBaseURL)
|
||||
// required to test sftpfs
|
||||
|
@ -13025,12 +13026,14 @@ func TestDefender(t *testing.T) {
|
|||
req.RemoteAddr = remoteAddr
|
||||
rr = executeRequest(req)
|
||||
checkResponseCode(t, http.StatusOK, rr)
|
||||
assert.Empty(t, rr.Header().Get("Cache-Control"))
|
||||
|
||||
req, err = http.NewRequest(http.MethodGet, "/.well-known/acme-challenge/foo", nil)
|
||||
assert.NoError(t, err)
|
||||
req.RemoteAddr = remoteAddr
|
||||
rr = executeRequest(req)
|
||||
checkResponseCode(t, http.StatusNotFound, rr)
|
||||
assert.Equal(t, "no-cache, no-store, max-age=0, must-revalidate, private", rr.Header().Get("Cache-Control"))
|
||||
|
||||
_, err = httpdtest.RemoveUser(user, http.StatusOK)
|
||||
assert.NoError(t, err)
|
||||
|
|
|
@ -2942,6 +2942,7 @@ func TestSecureMiddlewareIntegration(t *testing.T) {
|
|||
STSIncludeSubdomains: true,
|
||||
STSPreload: true,
|
||||
ContentTypeNosniff: true,
|
||||
CacheControl: "private",
|
||||
},
|
||||
},
|
||||
enableWebAdmin: true,
|
||||
|
@ -2961,6 +2962,7 @@ func TestSecureMiddlewareIntegration(t *testing.T) {
|
|||
r.Host = "127.0.0.1"
|
||||
server.router.ServeHTTP(rr, r)
|
||||
assert.Equal(t, http.StatusForbidden, rr.Code)
|
||||
assert.Equal(t, "no-cache, no-store, max-age=0, must-revalidate, private", rr.Header().Get("Cache-Control"))
|
||||
|
||||
rr = httptest.NewRecorder()
|
||||
r.Header.Set(forwardedHostHeader, "www.sftpgo.com")
|
||||
|
|
|
@ -586,3 +586,17 @@ func checkPartialAuth(w http.ResponseWriter, r *http.Request, audience string, t
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func cacheControlMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate, private")
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func cleanCacheControlMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Del("Cache-Control")
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1242,7 +1242,6 @@ func (s *httpdServer) initializeRouter() {
|
|||
s.router.Use(s.parseHeaders)
|
||||
s.router.Use(logger.NewStructuredLogger(logger.GetLogger()))
|
||||
s.router.Use(middleware.Recoverer)
|
||||
s.router.Use(middleware.Maybe(s.checkConnection, s.mustCheckPath))
|
||||
if s.binding.Security.Enabled {
|
||||
secureMiddleware := secure.New(secure.Options{
|
||||
AllowedHosts: s.binding.Security.AllowedHosts,
|
||||
|
@ -1258,6 +1257,9 @@ func (s *httpdServer) initializeRouter() {
|
|||
CrossOriginOpenerPolicy: s.binding.Security.CrossOriginOpenerPolicy,
|
||||
})
|
||||
secureMiddleware.SetBadHostHandler(http.HandlerFunc(s.badHostHandler))
|
||||
if s.binding.Security.CacheControl == "private" {
|
||||
s.router.Use(cacheControlMiddleware)
|
||||
}
|
||||
s.router.Use(secureMiddleware.Handler)
|
||||
if s.binding.Security.HTTPSRedirect {
|
||||
s.router.Use(s.binding.Security.redirectHandler)
|
||||
|
@ -1278,6 +1280,7 @@ func (s *httpdServer) initializeRouter() {
|
|||
})
|
||||
s.router.Use(c.Handler)
|
||||
}
|
||||
s.router.Use(middleware.Maybe(s.checkConnection, s.mustCheckPath))
|
||||
s.router.Use(middleware.GetHead)
|
||||
s.router.Use(middleware.Maybe(middleware.StripSlashes, s.mustStripSlash))
|
||||
|
||||
|
@ -1487,6 +1490,7 @@ func (s *httpdServer) initializeRouter() {
|
|||
|
||||
if s.renderOpenAPI {
|
||||
s.router.Group(func(router chi.Router) {
|
||||
router.Use(cleanCacheControlMiddleware)
|
||||
router.Use(compressor.Handler)
|
||||
serveStaticDir(router, webOpenAPIPath, s.openAPIPath, false)
|
||||
})
|
||||
|
@ -1495,6 +1499,7 @@ func (s *httpdServer) initializeRouter() {
|
|||
|
||||
if s.enableWebAdmin || s.enableWebClient {
|
||||
s.router.Group(func(router chi.Router) {
|
||||
router.Use(cleanCacheControlMiddleware)
|
||||
router.Use(compressor.Handler)
|
||||
serveStaticDir(router, webStaticFilesPath, s.staticFilesPath, true)
|
||||
})
|
||||
|
|
|
@ -311,7 +311,8 @@
|
|||
"content_type_nosniff": false,
|
||||
"content_security_policy": "",
|
||||
"permissions_policy": "",
|
||||
"cross_origin_opener_policy": ""
|
||||
"cross_origin_opener_policy": "",
|
||||
"cache_control": ""
|
||||
},
|
||||
"branding": {
|
||||
"web_admin": {
|
||||
|
|
Loading…
Reference in a new issue