From 85d6d5371bc39150755b95acc1fa3a7b34657eed Mon Sep 17 00:00:00 2001
From: jerebear12 <72420925+jerebear12@users.noreply.github.com>
Date: Tue, 27 Feb 2024 10:38:55 -0600
Subject: [PATCH] Disable filer UI in configuration (#5297)

* Add filer.ui.enabled configuration property

* Add filer.expose_directory_metadata to config

* Ammend commit

* Remove ShowUI reference

* Update all routes that allow directory metadata

* Add cmd flag to server.go
---
 weed/command/filer.go                         | 2 ++
 weed/command/scaffold/security.toml           | 7 +++++++
 weed/command/server.go                        | 1 +
 weed/server/filer_server.go                   | 5 +++++
 weed/server/filer_server_handlers_read.go     | 4 ++--
 weed/server/filer_server_handlers_read_dir.go | 6 ++++++
 6 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/weed/command/filer.go b/weed/command/filer.go
index cee886d18..1d8a6c4b8 100644
--- a/weed/command/filer.go
+++ b/weed/command/filer.go
@@ -62,6 +62,7 @@ type FilerOptions struct {
 	downloadMaxMBps         *int
 	diskType                *string
 	allowedOrigins          *string
+	exposeDirectoryData     *bool
 }
 
 func init() {
@@ -93,6 +94,7 @@ func init() {
 	f.downloadMaxMBps = cmdFiler.Flag.Int("downloadMaxMBps", 0, "download max speed for each download request, in MB per second")
 	f.diskType = cmdFiler.Flag.String("disk", "", "[hdd|ssd|<tag>] hard drive or solid state drive or any tag")
 	f.allowedOrigins = cmdFiler.Flag.String("allowedOrigins", "*", "comma separated list of allowed origins")
+	f.exposeDirectoryData = cmdFiler.Flag.Bool("exposeDirectoryData", true, "whether to return directory metadata and content in Filer UI")
 
 	// start s3 on filer
 	filerStartS3 = cmdFiler.Flag.Bool("s3", false, "whether to start S3 gateway")
diff --git a/weed/command/scaffold/security.toml b/weed/command/scaffold/security.toml
index 9626ee58c..c5b2a563c 100644
--- a/weed/command/scaffold/security.toml
+++ b/weed/command/scaffold/security.toml
@@ -24,6 +24,13 @@ expires_after_seconds = 10           # seconds
 [access]
 ui = false
 
+# by default the filer UI is enabled. This can be a security risk if the filer is exposed to the public
+# and the JWT for reads is not set. If you don't want the public to have access to the objects in your
+# storage, and you haven't set the JWT for reads it is wise to disable access to directory metadata.
+# This disables access to the Filer UI, and will no longer return directory metadata in GET requests.
+[filer.expose_directory_metadata]
+enabled = true
+
 # this jwt signing key is read by master and volume server, and it is used for read operations:
 # - the Master server generates the JWT, which can be used to read a certain file on a volume server
 # - the Volume server validates the JWT on reading
diff --git a/weed/command/server.go b/weed/command/server.go
index b8ef25fad..63133b80c 100644
--- a/weed/command/server.go
+++ b/weed/command/server.go
@@ -118,6 +118,7 @@ func init() {
 	filerOptions.showUIDirectoryDelete = cmdServer.Flag.Bool("filer.ui.deleteDir", true, "enable filer UI show delete directory button")
 	filerOptions.downloadMaxMBps = cmdServer.Flag.Int("filer.downloadMaxMBps", 0, "download max speed for each download request, in MB per second")
 	filerOptions.diskType = cmdServer.Flag.String("filer.disk", "", "[hdd|ssd|<tag>] hard drive or solid state drive or any tag")
+	filerOptions.exposeDirectoryData = cmdServer.Flag.Bool("filer.exposeDirectoryData", true, "expose directory data via filer. If false, filer UI will be innaccessible.")
 
 	serverOptions.v.port = cmdServer.Flag.Int("volume.port", 8080, "volume server http listen port")
 	serverOptions.v.portGrpc = cmdServer.Flag.Int("volume.port.grpc", 0, "volume server grpc listen port")
diff --git a/weed/server/filer_server.go b/weed/server/filer_server.go
index a04fd1910..9428c2edf 100644
--- a/weed/server/filer_server.go
+++ b/weed/server/filer_server.go
@@ -72,6 +72,7 @@ type FilerOption struct {
 	DownloadMaxBytesPs    int64
 	DiskType              string
 	AllowedOrigins        []string
+	ExposeDirectoryData   bool
 }
 
 type FilerServer struct {
@@ -115,6 +116,10 @@ func NewFilerServer(defaultMux, readonlyMux *http.ServeMux, option *FilerOption)
 	domains := strings.Split(allowedOrigins, ",")
 	option.AllowedOrigins = domains
 
+	v.SetDefault("filer.expose_directory_metadata.enabled", true)
+	returnDirMetadata := v.GetBool("filer.expose_directory_metadata.enabled")
+	option.ExposeDirectoryData = returnDirMetadata
+
 	fs = &FilerServer{
 		option:                option,
 		grpcDialOption:        security.LoadClientTLS(util.GetViper(), "grpc.filer"),
diff --git a/weed/server/filer_server_handlers_read.go b/weed/server/filer_server_handlers_read.go
index d1cd3beae..0f4037237 100644
--- a/weed/server/filer_server_handlers_read.go
+++ b/weed/server/filer_server_handlers_read.go
@@ -117,7 +117,7 @@ func (fs *FilerServer) GetOrHeadHandler(w http.ResponseWriter, r *http.Request)
 			w.WriteHeader(http.StatusForbidden)
 			return
 		}
-		if query.Get("metadata") == "true" {
+		if query.Get("metadata") == "true" && fs.option.ExposeDirectoryData != false {
 			writeJsonQuiet(w, r, http.StatusOK, entry)
 			return
 		}
@@ -135,7 +135,7 @@ func (fs *FilerServer) GetOrHeadHandler(w http.ResponseWriter, r *http.Request)
 		return
 	}
 
-	if query.Get("metadata") == "true" {
+	if query.Get("metadata") == "true" && fs.option.ExposeDirectoryData != false {
 		if query.Get("resolveManifest") == "true" {
 			if entry.Chunks, _, err = filer.ResolveChunkManifest(
 				fs.filer.MasterClient.GetLookupFileIdFunction(),
diff --git a/weed/server/filer_server_handlers_read_dir.go b/weed/server/filer_server_handlers_read_dir.go
index 2060e3374..be38fba1d 100644
--- a/weed/server/filer_server_handlers_read_dir.go
+++ b/weed/server/filer_server_handlers_read_dir.go
@@ -18,6 +18,11 @@ import (
 // is empty.
 func (fs *FilerServer) listDirectoryHandler(w http.ResponseWriter, r *http.Request) {
 
+	if fs.option.ExposeDirectoryData == false {
+		http.NotFound(w, r)
+		return
+	}
+
 	stats.FilerHandlerCounter.WithLabelValues(stats.DirList).Inc()
 
 	path := r.URL.Path
@@ -95,4 +100,5 @@ func (fs *FilerServer) listDirectoryHandler(w http.ResponseWriter, r *http.Reque
 	if err != nil {
 		glog.V(0).Infof("Template Execute Error: %v", err)
 	}
+
 }