diff --git a/Makefile b/Makefile index cb6664e..8cbf132 100755 --- a/Makefile +++ b/Makefile @@ -26,10 +26,12 @@ test: go test -run TestNormal killall gossa + sleep 1 -make run-extra & go test -run TestExtra killall gossa + sleep 1 -make run-ro & go test -run TestRo diff --git a/gossa.go b/gossa.go index 19f4db6..a5a0b35 100755 --- a/gossa.go +++ b/gossa.go @@ -31,7 +31,7 @@ var symlinks = flag.Bool("symlinks", false, "follow symlinks \033[4mWARNING\033[ var verb = flag.Bool("verb", false, "verbosity") var skipHidden = flag.Bool("k", true, "\nskip hidden files") var ro = flag.Bool("ro", false, "read only mode (no upload, rename, move, etc...)") -var initPath = "." +var rootPath = "" var handler http.Handler @@ -196,10 +196,7 @@ func zipRPC(w http.ResponseWriter, r *http.Request) { defer exitPath(w, "zip", zipPath) zipFullPath := enforcePath(zipPath) _, err := os.Lstat(zipFullPath) - if err != nil { - panic("zip path doesnt exist") - } - + check(err) w.Header().Add("Content-Disposition", "attachment; filename=\""+zipName+".zip\"") zipWriter := zip.NewWriter(w) defer zipWriter.Close() @@ -212,11 +209,9 @@ func zipRPC(w http.ResponseWriter, r *http.Request) { rel, err := filepath.Rel(zipFullPath, path) check(err) - if *skipHidden && strings.HasPrefix(rel, ".") { return nil // hidden files not allowed } - if f.Mode()&os.ModeSymlink != 0 { panic(errors.New("symlink not allowed in zip downloads")) // filepath.Walk doesnt support symlinks } @@ -259,7 +254,7 @@ func rpc(w http.ResponseWriter, r *http.Request) { } func enforcePath(p string) string { - joined := filepath.Join(initPath, strings.TrimPrefix(p, *extraPath)) + joined := filepath.Join(rootPath, strings.TrimPrefix(p, *extraPath)) fp, err := filepath.Abs(joined) sl, _ := filepath.EvalSymlinks(fp) // err skipped as it would error for unexistent files (RPC check). The actual behaviour is tested below @@ -267,7 +262,7 @@ func enforcePath(p string) string { // ... or if path doesnt contain the prefix path we expect, // ... or if we're skipping hidden folders, and one is requested, // ... or if we're skipping symlinks, path exists, and a symlink out of bound requested - if err != nil || !strings.HasPrefix(fp, initPath) || *skipHidden && strings.Contains(p, "/.") || !*symlinks && len(sl) > 0 && !strings.HasPrefix(sl, initPath) { + if err != nil || !strings.HasPrefix(fp, rootPath) || *skipHidden && strings.Contains(p, "/.") || !*symlinks && len(sl) > 0 && !strings.HasPrefix(sl, rootPath) { panic(errors.New("invalid path")) } @@ -275,18 +270,16 @@ func enforcePath(p string) string { } func main() { - var err error - flag.Usage = func() { + if flag.Parse(); len(flag.Args()) > 0 { + rootPath = flag.Args()[0] + } else { fmt.Printf("\nusage: ./gossa ~/directory-to-share\n\n") flag.PrintDefaults() + os.Exit(1) } - flag.Parse() - if len(flag.Args()) > 0 { - initPath = flag.Args()[0] - } - - initPath, err = filepath.Abs(initPath) + var err error + rootPath, err = filepath.Abs(rootPath) check(err) templateStr = strings.Replace(templateStr, "css_will_be_here", styleCss, 1) @@ -299,11 +292,10 @@ func main() { http.HandleFunc(*extraPath+"rpc", rpc) http.HandleFunc(*extraPath+"post", upload) } - http.HandleFunc(*extraPath+"zip", zipRPC) http.HandleFunc("/", doContent) - handler = http.StripPrefix(*extraPath, http.FileServer(http.Dir(initPath))) - fmt.Printf("Gossa starting on directory %s\nListening on http://%s:%s%s\n", initPath, *host, *port, *extraPath) + handler = http.StripPrefix(*extraPath, http.FileServer(http.Dir(rootPath))) + fmt.Printf("Gossa starting on directory %s\nListening on http://%s:%s%s\n", rootPath, *host, *port, *extraPath) err = http.ListenAndServe(*host+":"+*port, nil) check(err) } diff --git a/gossa_test.go b/gossa_test.go index 861b059..cd5172c 100644 --- a/gossa_test.go +++ b/gossa_test.go @@ -135,6 +135,7 @@ func doTestRegular(t *testing.T, url string, testExtra bool) { // ~~~~~~~~~~~~~~~~~ fmt.Println("\r\n~~~~~~~~~~ test zip invalid path") body0 = get(t, url+"zip?zipPath=%2Ftmp&zipName=subdir") + println(body0) if body0 != `error` { t.Fatal("zip passed for invalid path") } @@ -200,12 +201,20 @@ func doTestRegular(t *testing.T, url string, testExtra bool) { // ~~~~~~~~~~~~~~~~~ fmt.Println("\r\n~~~~~~~~~~ test symlink, should succeed: ", testExtra) - body0 = get(t, url+"/support/readme.md") - hasReadme := strings.Contains(body0, `the master branch is automatically built and pushed`) + body0 = get(t, url+"/support/") + hasListing := strings.Contains(body0, `readme.md`) + body1 = get(t, url+"/support/readme.md") + hasReadme := strings.Contains(body1, `the master branch is automatically built and pushed`) + if !testExtra && hasReadme { - t.Fatal("error symlink reached where illegal") + t.Fatal("error symlink file reached where illegal") } else if testExtra && !hasReadme { - t.Fatal("error symlink unreachable") + t.Fatal("error symlink file unreachable") + } + if !testExtra && hasListing { + t.Fatal("error symlink folder reached where illegal") + } else if testExtra && !hasListing { + t.Fatal("error symlink folder unreachable") } if testExtra { @@ -298,7 +307,7 @@ func doTestReadonly(t *testing.T, url string) { path = "%2F%E1%84%92%E1%85%A1%20%E1%84%92%E1%85%A1" // "하 하" encoded payload = "123 하" body0 = postDummyFile(t, url, path, payload) - body1 = get(t, url+path) + get(t, url+path) if body0 == `ok` { t.Fatal("post file passed - should not be allowed") } @@ -306,7 +315,7 @@ func doTestReadonly(t *testing.T, url string) { // ~~~~~~~~~~~~~~~~~ fmt.Println("\r\n~~~~~~~~~~ test mv rpc") body0 = postJSON(t, url+"rpc", `{"call":"mv","args":["/AAA", "/hols/AAA"]}`) - body1 = fetchAndTestDefault(t, url) + fetchAndTestDefault(t, url) if body0 == `ok` { t.Fatal("mv rpc passed - should not be allowed") }