Skip to content

Commit

Permalink
Better logging / rename vars
Browse files Browse the repository at this point in the history
  • Loading branch information
puhitaku committed Mar 21, 2023
1 parent 25ec12b commit b7c10a3
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 16 deletions.
67 changes: 59 additions & 8 deletions server/path.go
Original file line number Diff line number Diff line change
@@ -1,33 +1,84 @@
package server

import (
"errors"
"fmt"
"path/filepath"
"strings"

"github.com/rs/zerolog"
)

type InvalidPathError struct {
PathRequest string
PathAbs string
PathEval string
Reason reason

BaseErr error
}

type reason string

const (
AbsFail reason = "failed to get the absolute path"
EvalFail reason = "failed to evaluate symlinks"
OutOfRoot reason = "out of the root directory"
)

var invalidPathError = errors.New("invalid path, or not found")
func (i InvalidPathError) Error() string {
// Prevent unexpected exposure of the actual reason, for security
return "invalid path, or not found"
}

func (i InvalidPathError) Unwrap() error {
return i.BaseErr
}

func (i InvalidPathError) MarshalZerologObject(e *zerolog.Event) {
e.Str("pathRequest", i.PathRequest)
if i.PathAbs != "" {
e.Str("pathAbs", i.PathAbs)
}
if i.PathEval != "" {
e.Str("pathEval", i.PathEval)
}
e.Str("reason", string(i.Reason))
e.AnErr("baseErr", i.BaseErr)
}

func evaluatePath(untrustedPath, trustedRoot string, evalSymlink bool) (string, error) {
joined := filepath.Join(trustedRoot, untrustedPath) // Join() also cleans the path
func evaluatePath(requestPath, trustedRoot string, evalSymlink bool) (string, error) {
joined := filepath.Join(trustedRoot, requestPath) // Join() also cleans the path
abs, err := filepath.Abs(joined)
if err != nil {
return "", fmt.Errorf("failed to get the absolute path: %w", err)
return "", InvalidPathError{
PathRequest: requestPath,
Reason: AbsFail,
BaseErr: err,
}
}

evaluated := abs

if evalSymlink {
evaluated, err = filepath.EvalSymlinks(abs)
if err != nil {
return "", invalidPathError
return "", InvalidPathError{
PathRequest: requestPath,
PathAbs: abs,
Reason: EvalFail,
BaseErr: err,
}
}
}

trusted := strings.HasPrefix(evaluated, trustedRoot)
if !trusted {
return "", invalidPathError
return "", InvalidPathError{
PathRequest: requestPath,
PathAbs: abs,
PathEval: evaluated,
Reason: OutOfRoot,
BaseErr: err,
}
}

return evaluated, nil
Expand Down
27 changes: 19 additions & 8 deletions server/server.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package server

import (
"errors"
"io"
"os"

Expand All @@ -15,13 +16,18 @@ func SetRoot(p string) {
}

// ReadHandler is called when client starts file download from server
func ReadHandler(filename string, rf io.ReaderFrom) error {
func ReadHandler(requestedPath string, rf io.ReaderFrom) error {
reqID := ulid.Make().String()
log.Info().Str("requestId", reqID).Msgf("read request: %s", filename)
log.Info().Str("requestId", reqID).Msgf("read request: %s", requestedPath)

evalPath, err := evaluatePath(filename, root, true)
evalPath, err := evaluatePath(requestedPath, root, true)
if err != nil {
log.Error().Str("requestId", reqID).Msgf("invalid path specified: %s", err)
perr := InvalidPathError{}
if errors.As(err, &perr) {
log.Error().Str("requestId", reqID).EmbedObject(perr).Msgf("failed to evaluate path")
} else {
log.Error().Str("requestId", reqID).Msgf("failed to evaluate path: %s", err)
}
return err
}

Expand All @@ -44,13 +50,18 @@ func ReadHandler(filename string, rf io.ReaderFrom) error {
}

// WriteHandler is called when client starts file upload to server
func WriteHandler(filename string, wt io.WriterTo) error {
func WriteHandler(requestedPath string, wt io.WriterTo) error {
reqID := ulid.Make().String()
log.Info().Str("requestId", reqID).Msgf("write request: %s", filename)
log.Info().Str("requestId", reqID).Msgf("write request: %s", requestedPath)

evalPath, err := evaluatePath(filename, root, false)
evalPath, err := evaluatePath(requestedPath, root, false)
if err != nil {
log.Error().Str("requestId", reqID).Msgf("invalid path specified: %s", err)
perr := InvalidPathError{}
if errors.As(err, &perr) {
log.Error().Str("requestId", reqID).EmbedObject(perr).Msgf("failed to evaluate path")
} else {
log.Error().Str("requestId", reqID).Msgf("failed to evaluate path: %s", err)
}
return err
}

Expand Down

0 comments on commit b7c10a3

Please sign in to comment.