Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 27 additions & 4 deletions gossa.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@ func check(e error) {

func exitPath(w http.ResponseWriter, s ...interface{}) {
if r := recover(); r != nil {
log.Println("error", s, r)
if *verb {
log.Printf("error %v: %v", s, r)
} else {
log.Println("error", s, r)
}
w.WriteHeader(500)
w.Write([]byte("error"))
} else if *verb {
Expand Down Expand Up @@ -183,6 +187,7 @@ func upload(w http.ResponseWriter, r *http.Request) {
}
dst, err := os.Create(enforcePath(path))
check(err)
defer dst.Close()
io.Copy(dst, part)
w.Write([]byte("ok"))
}
Expand Down Expand Up @@ -221,8 +226,8 @@ func zipRPC(w http.ResponseWriter, r *http.Request) {
check(err)
file, err := os.Open(path)
check(err)
defer file.Close()
_, err = io.Copy(headerWriter, file)
file.Close()
check(err)
return nil
})
Expand Down Expand Up @@ -259,6 +264,8 @@ func rpc(w http.ResponseWriter, r *http.Request) {
hash = sha256.New()
case "sha512":
hash = sha512.New()
default:
check(errors.New("unsupported hash algorithm: " + rpc.Args[1]))
}
_, err = io.Copy(hash, file)
check(err)
Expand All @@ -272,15 +279,17 @@ func rpc(w http.ResponseWriter, r *http.Request) {
}

func enforcePath(p string) string {
joined := filepath.Join(rootPath, strings.TrimPrefix(p, *extraPath))
// Clean the path to remove any . or .. components
cleanPath := filepath.Clean(strings.TrimPrefix(p, *extraPath))
joined := filepath.Join(rootPath, cleanPath)
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

// panic if we had a error getting absolute path,
// ... 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, rootPath) || *skipHidden && strings.Contains(p, "/.") || !*symlinks && len(sl) > 0 && !strings.HasPrefix(sl, rootPath) {
if err != nil || !strings.HasPrefix(fp, rootPath) || *skipHidden && strings.Contains(cleanPath, "/.") || !*symlinks && len(sl) > 0 && !strings.HasPrefix(sl, rootPath) {
panic(errors.New("invalid path"))
}

Expand All @@ -299,6 +308,20 @@ func main() {
var err error
rootPath, err = filepath.Abs(rootPath)
check(err)

// Check if the directory exists and is accessible
stat, err := os.Stat(rootPath)
if err != nil {
if os.IsNotExist(err) {
log.Fatalf("Directory does not exist: %s", rootPath)
}
check(err)
}

if !stat.IsDir() {
log.Fatalf("Path is not a directory: %s", rootPath)
}

server := &http.Server{Addr: *host + ":" + *port, Handler: handler}

if !*ro {
Expand Down
8 changes: 4 additions & 4 deletions gossa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"archive/zip"
"bytes"
"fmt"
"io/ioutil"
"io"
"net/http"
"regexp"
"strings"
Expand All @@ -25,7 +25,7 @@ func trimSpaces(str string) string {
func getRaw(t *testing.T, url string) []byte {
resp, err := http.Get(url)
dieMaybe(t, err)
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
dieMaybe(t, err)
return body
}
Expand Down Expand Up @@ -59,15 +59,15 @@ func postDummyFile(t *testing.T, url string, path string, payload string) string
resp, err := http.DefaultClient.Do(req)
dieMaybe(t, err)
defer resp.Body.Close()
bodyS, err := ioutil.ReadAll(resp.Body)
bodyS, err := io.ReadAll(resp.Body)
dieMaybe(t, err)
return trimSpaces(string(bodyS))
}

func postJSON(t *testing.T, url string, what string) string {
resp, err := http.Post(url, "application/json", bytes.NewBuffer([]byte(what)))
dieMaybe(t, err)
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
dieMaybe(t, err)
return trimSpaces(string(body))
}
Expand Down