mirror of https://github.com/portainer/portainer
fix(api): add restrictions for the files served by the API (#903)
parent
5bf10b89b1
commit
5e74a3993b
|
@ -4,6 +4,7 @@ package portainer
|
||||||
const (
|
const (
|
||||||
ErrUnauthorized = Error("Unauthorized")
|
ErrUnauthorized = Error("Unauthorized")
|
||||||
ErrResourceAccessDenied = Error("Access denied to resource")
|
ErrResourceAccessDenied = Error("Access denied to resource")
|
||||||
|
ErrResourceNotFound = Error("Unable to find resource")
|
||||||
ErrUnsupportedDockerAPI = Error("Unsupported Docker API response")
|
ErrUnsupportedDockerAPI = Error("Unsupported Docker API response")
|
||||||
ErrMissingSecurityContext = Error("Unable to find security details in request context")
|
ErrMissingSecurityContext = Error("Unable to find security details in request context")
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,19 +1,36 @@
|
||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/portainer/portainer"
|
||||||
|
httperror "github.com/portainer/portainer/http/error"
|
||||||
|
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FileHandler represents an HTTP API handler for managing static files.
|
// FileHandler represents an HTTP API handler for managing static files.
|
||||||
type FileHandler struct {
|
type FileHandler struct {
|
||||||
http.Handler
|
http.Handler
|
||||||
|
Logger *log.Logger
|
||||||
|
allowedDirectories map[string]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFileHandler returns a new instance of FileHandler.
|
// NewFileHandler returns a new instance of FileHandler.
|
||||||
func NewFileHandler(assetPath string) *FileHandler {
|
func NewFileHandler(assetPath string) *FileHandler {
|
||||||
h := &FileHandler{
|
h := &FileHandler{
|
||||||
Handler: http.FileServer(http.Dir(assetPath)),
|
Handler: http.FileServer(http.Dir(assetPath)),
|
||||||
|
Logger: log.New(os.Stderr, "", log.LstdFlags),
|
||||||
|
allowedDirectories: map[string]bool{
|
||||||
|
"/": true,
|
||||||
|
"/css": true,
|
||||||
|
"/js": true,
|
||||||
|
"/images": true,
|
||||||
|
"/fonts": true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
@ -27,11 +44,18 @@ func isHTML(acceptContent []string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fileHandler *FileHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (handler *FileHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
requestDirectory := path.Dir(r.URL.Path)
|
||||||
|
if !handler.allowedDirectories[requestDirectory] {
|
||||||
|
httperror.WriteErrorResponse(w, portainer.ErrResourceNotFound, http.StatusNotFound, handler.Logger)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if !isHTML(r.Header["Accept"]) {
|
if !isHTML(r.Header["Accept"]) {
|
||||||
w.Header().Set("Cache-Control", "max-age=31536000")
|
w.Header().Set("Cache-Control", "max-age=31536000")
|
||||||
} else {
|
} else {
|
||||||
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||||
}
|
}
|
||||||
fileHandler.Handler.ServeHTTP(w, r)
|
|
||||||
|
handler.Handler.ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue