fix(api): add restrictions for the files served by the API (#903)

pull/619/merge
Anthony Lapenna 2017-05-29 22:10:36 +02:00 committed by GitHub
parent 5bf10b89b1
commit 5e74a3993b
2 changed files with 27 additions and 2 deletions

View File

@ -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")
) )

View File

@ -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)
} }