Path sanitation

master
Caj Larsson 3 years ago
parent e6e2f372dd
commit 82067ca87c

@ -57,6 +57,12 @@ func (s SwampFileService) getOrCreateNs(namespace_in string) *namespace.Namespac
func (s SwampFileService) SaveFile(ref swampfile.FileReference, src io.Reader, size int64) error { func (s SwampFileService) SaveFile(ref swampfile.FileReference, src io.Reader, size int64) error {
ns := s.getOrCreateNs(ref.UserAgent) ns := s.getOrCreateNs(ref.UserAgent)
err := ref.Clean(true)
if err != nil {
return err
}
if !ns.FileQuota.Allows(size) { if !ns.FileQuota.Allows(size) {
return namespace.ErrExceedQuota return namespace.ErrExceedQuota
} }
@ -78,9 +84,11 @@ func (s SwampFileService) SaveFile(ref swampfile.FileReference, src io.Reader, s
func (s SwampFileService) OpenOutFile(ref swampfile.FileReference) (swampfile.SwampOutFile, error) { func (s SwampFileService) OpenOutFile(ref swampfile.FileReference) (swampfile.SwampOutFile, error) {
ns := s.getOrCreateNs(ref.UserAgent) ns := s.getOrCreateNs(ref.UserAgent)
// if err == namespace.ErrNotExists { err := ref.Clean(true)
// return nil, err
// } if err != nil {
return nil, err
}
f, err := s.swamp_file_repo.Open(ref.Path, strconv.FormatInt(ns.ID, 10)) f, err := s.swamp_file_repo.Open(ref.Path, strconv.FormatInt(ns.ID, 10))

@ -11,9 +11,9 @@ import (
m_swampfile "caj-larsson/bog/infrastructure/memory/swampfile" m_swampfile "caj-larsson/bog/infrastructure/memory/swampfile"
) )
var file_ref1 = swampfile.FileReference{"ptah1", "ua1"} var file_ref1 = swampfile.FileReference{"/ptah1", "ns1"}
var file_ref2 = swampfile.FileReference{"path1", "ua2"} var file_ref2 = swampfile.FileReference{"/path1", "ns2"}
var file_ref3 = swampfile.FileReference{"path2", "ua1"} var file_ref3 = swampfile.FileReference{"/path2", "ns1"}
func NewTestSwampFileService() SwampFileService { func NewTestSwampFileService() SwampFileService {
file_repo := m_swampfile.NewRepository() file_repo := m_swampfile.NewRepository()
@ -67,12 +67,12 @@ func TestFileIsReadBack(t *testing.T) {
is.Equal(outfile.String(), "My bog data") is.Equal(outfile.String(), "My bog data")
} }
func TestUAIsolation(t *testing.T) { func TestNSIsolation(t *testing.T) {
is := is.New(t) is := is.New(t)
s := NewTestSwampFileService() s := NewTestSwampFileService()
ns1_file := bytes.NewBufferString("My bog data ua1") ns1_file := bytes.NewBufferString("My bog data ns1")
ns2_file := bytes.NewBufferString("My bog data ua2") ns2_file := bytes.NewBufferString("My bog data ns2")
_ = s.SaveFile(file_ref1, ns1_file, int64(ns1_file.Len())) _ = s.SaveFile(file_ref1, ns1_file, int64(ns1_file.Len()))
_ = s.SaveFile(file_ref2, ns2_file, int64(ns2_file.Len())) _ = s.SaveFile(file_ref2, ns2_file, int64(ns2_file.Len()))
@ -82,11 +82,26 @@ func TestUAIsolation(t *testing.T) {
outfile := bytes.NewBufferString("") outfile := bytes.NewBufferString("")
_, _ = outfile.ReadFrom(outswampfile) _, _ = outfile.ReadFrom(outswampfile)
is.Equal(outfile.String(), "My bog data ua1") is.Equal(outfile.String(), "My bog data ns1")
} }
func TestCleanPath(t *testing.T) {
func TestPathStrictMode(t *testing.T) {
is := is.New(t) is := is.New(t)
s := NewTestSwampFileService()
ns_file := bytes.NewBufferString("My bog data ns1")
ref := swampfile.FileReference {
"/path/../with/../backrefs",
"ns1",
}
outfile, err := s.OpenOutFile(ref)
is.Equal(err, swampfile.ErrUnacceptablePath)
is.Equal(outfile, nil)
is.Equal(CleanPath("/"), "/") err = s.SaveFile(ref, ns_file, int64(ns_file.Len()))
is.Equal(err, swampfile.ErrUnacceptablePath)
} }

@ -19,4 +19,5 @@ var (
ErrNotExists = errors.New("row not exists") ErrNotExists = errors.New("row not exists")
ErrUpdateFailed = errors.New("update failed") ErrUpdateFailed = errors.New("update failed")
ErrDeleteFailed = errors.New("delete failed") ErrDeleteFailed = errors.New("delete failed")
ErrUnacceptablePath = errors.New("unacceptable path")
) )

@ -2,6 +2,9 @@ package swampfile
import ( import (
"io" "io"
"path"
"path/filepath"
"strings"
"time" "time"
) )
@ -27,3 +30,15 @@ type FileReference struct {
Path string Path string
UserAgent string UserAgent string
} }
func (fr *FileReference) Clean(strict bool) error {
c := filepath.FromSlash(path.Clean("/" + strings.Trim(fr.Path, "/")))
if c != fr.Path && strict {
return ErrUnacceptablePath
}
fr.Path = c
return nil
}

@ -0,0 +1,44 @@
package swampfile
import (
"github.com/matryer/is"
"testing"
)
func TestSwampPathNotStrict(t *testing.T) {
cases := []struct {
dirty string
clean string
}{
{"/", "/"},
{"..", "/"},
{"/../a", "/a"},
{"/../a/../a", "/a"},
{"../b", "/b"},
}
is := is.New(t)
for _, tc := range cases {
rf := FileReference{
tc.dirty,
"ns",
}
err := rf.Clean(false)
is.NoErr(err)
is.Equal(rf.Path, tc.clean)
}
}
func TestSwampPathStrict(t *testing.T) {
is := is.New(t)
rf := FileReference{
"/a/../b",
"ns",
}
err := rf.Clean(true)
is.Equal(err, ErrUnacceptablePath)
}
Loading…
Cancel
Save