From 7066e5ccb2a086ffc2db980f2219585c46acba04 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Tue, 23 Oct 2018 14:26:59 +0300 Subject: [PATCH] denied patterns flag option fixes #12 --- README.md | 7 ++----- spark.go | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index cb25ed0..9718ec7 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ Usage of spark: -sslPort="10433": SSL listening port -status=200: Returned HTTP status code -path="/": URL path + -deny="": Sesitive directory or file patterns to be denied when listing path (comma sperated) ``` @@ -27,6 +28,7 @@ $ spark message.html $ spark "

Out of order

Working on it...

" $ spark static_site/ $ spark -port 80 -sslPort 443 "

Ooops!

" +$ spark -deny ".git*,LICENSE" ~/go/rif/spark ``` To quickly generate a ssl certificate run: @@ -43,8 +45,3 @@ go get github.com/rif/spark - static binaries (linux/arm/osx/windows): Binary downloads - -## crossbuild - -Just run ./crossbuild.sh (needs go 1.5 or later). It also compresses the binaries with upx, comment those lines if you don't need compression. - diff --git a/spark.go b/spark.go index f4aa317..374302d 100644 --- a/spark.go +++ b/spark.go @@ -6,6 +6,8 @@ import ( "log" "net/http" "os" + "path/filepath" + "strings" ) var ( @@ -13,6 +15,7 @@ var ( port = flag.String("port", "8080", "Listening port") sslPort = flag.String("sslPort", "10433", "SSL listening port") path = flag.String("path", "/", "URL path") + deny = flag.String("deny", "", "Sesitive directories or files to be forbidden when listing path (comma sperated)") status = flag.Int("status", 200, "Returned HTTP status code") cert = flag.String("cert", "cert.pem", "SSL certificate path") key = flag.String("key", "key.pem", "SSL private Key path") @@ -26,6 +29,35 @@ func (h bytesHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { w.Write(h) } +func isDenied(path, denyList string) bool { + if len(denyList) == 0 { + return false + } + for _, pathElement := range strings.Split(path, string(filepath.Separator)) { + for _, denyElement := range strings.Split(denyList, ",") { + match, err := filepath.Match(strings.TrimSpace(denyElement), pathElement) + if err != nil { + log.Print("error matching file path element: ", err) + } + if match { + return true + } + } + } + return false +} + +type protectdFileSystem struct { + fs http.FileSystem +} + +func (pfs protectdFileSystem) Open(path string) (http.File, error) { + if isDenied(path, *deny) { + return nil, os.ErrPermission + } + return pfs.fs.Open(path) +} + func main() { flag.Parse() listen := *address + ":" + *port @@ -38,7 +70,7 @@ func main() { if fi, err := os.Stat(body); err == nil { switch mode := fi.Mode(); { case mode.IsDir(): - handler = http.StripPrefix(*path, http.FileServer(http.Dir(body))) + handler = http.StripPrefix(*path, http.FileServer(protectdFileSystem{http.Dir(body)})) case mode.IsRegular(): if content, err := ioutil.ReadFile(body); err != nil { log.Fatal("Error reading file: ", err)