diff --git a/api/cli/cli.go b/api/cli/cli.go index c4cde81ec..a343195f4 100644 --- a/api/cli/cli.go +++ b/api/cli/cli.go @@ -7,6 +7,7 @@ import ( "github.com/portainer/portainer" "os" + "path/filepath" "strings" "gopkg.in/alecthomas/kingpin.v2" @@ -54,6 +55,15 @@ func (*Service) ParseFlags(version string) (*portainer.CLIFlags, error) { } kingpin.Parse() + + if !filepath.IsAbs(*flags.Assets) { + ex, err := os.Executable() + if err != nil { + panic(err) + } + *flags.Assets = filepath.Join(filepath.Dir(ex), *flags.Assets) + } + return flags, nil } diff --git a/api/cli/defaults.go b/api/cli/defaults.go index 1b1c86a3b..2d350c1c7 100644 --- a/api/cli/defaults.go +++ b/api/cli/defaults.go @@ -5,7 +5,7 @@ package cli const ( defaultBindAddress = ":9000" defaultDataDirectory = "/data" - defaultAssetsDirectory = "/" + defaultAssetsDirectory = "./" defaultNoAuth = "false" defaultNoAnalytics = "false" defaultTLSVerify = "false" diff --git a/api/cli/defaults_windows.go b/api/cli/defaults_windows.go index 914ee3d2a..a94657258 100644 --- a/api/cli/defaults_windows.go +++ b/api/cli/defaults_windows.go @@ -3,7 +3,7 @@ package cli const ( defaultBindAddress = ":9000" defaultDataDirectory = "C:\\data" - defaultAssetsDirectory = "/" + defaultAssetsDirectory = "./" defaultNoAuth = "false" defaultNoAnalytics = "false" defaultTLSVerify = "false" diff --git a/api/http/handler/file.go b/api/http/handler/file.go index 2191169ac..efc7e2b77 100644 --- a/api/http/handler/file.go +++ b/api/http/handler/file.go @@ -3,35 +3,22 @@ package handler import ( "os" - "github.com/portainer/portainer" - httperror "github.com/portainer/portainer/http/error" - "log" "net/http" - "path" "strings" ) // FileHandler represents an HTTP API handler for managing static files. type FileHandler struct { http.Handler - Logger *log.Logger - allowedDirectories map[string]bool + Logger *log.Logger } // NewFileHandler returns a new instance of FileHandler. -func NewFileHandler(assetPath string) *FileHandler { +func NewFileHandler(assetPublicPath string) *FileHandler { h := &FileHandler{ - Handler: http.FileServer(http.Dir(assetPath)), + Handler: http.FileServer(http.Dir(assetPublicPath)), Logger: log.New(os.Stderr, "", log.LstdFlags), - allowedDirectories: map[string]bool{ - "/": true, - "/css": true, - "/js": true, - "/images": true, - "/fonts": true, - "/ico": true, - }, } return h } @@ -46,17 +33,10 @@ func isHTML(acceptContent []string) bool { } 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"]) { w.Header().Set("Cache-Control", "max-age=31536000") } else { w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") } - handler.Handler.ServeHTTP(w, r) } diff --git a/api/http/server.go b/api/http/server.go index e3f31e8d1..93d874cb3 100644 --- a/api/http/server.go +++ b/api/http/server.go @@ -7,6 +7,7 @@ import ( "github.com/portainer/portainer/http/security" "net/http" + "path/filepath" ) // Server implements the portainer.Server interface @@ -42,7 +43,7 @@ func (server *Server) Start() error { requestBouncer := security.NewRequestBouncer(server.JWTService, server.TeamMembershipService, server.AuthDisabled) proxyManager := proxy.NewManager(server.ResourceControlService, server.TeamMembershipService, server.SettingsService) - var fileHandler = handler.NewFileHandler(server.AssetsPath) + var fileHandler = handler.NewFileHandler(filepath.Join(server.AssetsPath, "public")) var authHandler = handler.NewAuthHandler(requestBouncer, server.AuthDisabled) authHandler.UserService = server.UserService authHandler.CryptoService = server.CryptoService diff --git a/gruntfile.js b/gruntfile.js index 2bae53d25..d7ae868d2 100644 --- a/gruntfile.js +++ b/gruntfile.js @@ -57,7 +57,7 @@ module.exports = function (grunt) { // Project configuration. grunt.initConfig({ - distdir: 'dist', + distdir: 'dist/public', shippedDockerVersion: '17.09.0-ce', pkg: grunt.file.readJSON('package.json'), config: { @@ -72,8 +72,8 @@ module.exports = function (grunt) { css: ['assets/css/app.css'] }, clean: { - all: ['<%= distdir %>/*'], - app: ['<%= distdir %>/*', '!<%= distdir %>/portainer*', '!<%= distdir %>/docker*'], + all: ['<%= distdir %>/../*'], + app: ['<%= distdir %>/*', '!<%= distdir %>/../portainer*', '!<%= distdir %>/../docker*'], tmpl: ['<%= distdir %>/templates'], tmp: ['<%= distdir %>/js/*', '!<%= distdir %>/js/app.*.js', '<%= distdir %>/css/*', '!<%= distdir %>/css/app.*.css'] }, @@ -93,7 +93,8 @@ module.exports = function (grunt) { release: { src: '<%= src.html %>', options: { - root: '<%= distdir %>' + root: '<%= distdir %>', + dest: '<%= distdir %>' } } }, @@ -187,7 +188,7 @@ module.exports = function (grunt) { run: { command: [ 'docker rm -f portainer', - 'docker run -d -p 9000:9000 -v $(pwd)/dist:/app -v /tmp/portainer:/data -v /var/run/docker.sock:/var/run/docker.sock:z --name portainer portainer/base /app/portainer-linux-' + arch + ' --no-analytics -a /app' + 'docker run -d -p 9000:9000 -v $(pwd)/dist:/app -v /tmp/portainer:/data -v /var/run/docker.sock:/var/run/docker.sock:z --name portainer portainer/base /app/portainer-linux-' + arch + ' --no-analytics' ].join(';') }, downloadDockerBinary: {