Skip to content
This repository was archived by the owner on Jun 25, 2022. It is now read-only.

Commit bcc60f5

Browse files
hdmmarkbates
authored andcommitted
Improve file resolution with the Disk and fallback resolver (#231)
1 parent 9966810 commit bcc60f5

3 files changed

Lines changed: 78 additions & 14 deletions

File tree

v2/box.go

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import (
1515
"github.com/gobuffalo/packd"
1616
"github.com/gobuffalo/packr/v2/file"
1717
"github.com/gobuffalo/packr/v2/file/resolver"
18-
"github.com/gobuffalo/packr/v2/plog"
1918
"github.com/gobuffalo/packr/v2/internal/takeon/github.com/markbates/oncer"
19+
"github.com/gobuffalo/packr/v2/plog"
2020
)
2121

2222
var _ packd.Box = &Box{}
@@ -28,12 +28,12 @@ var _ packd.Finder = &Box{}
2828
// Box represent a folder on a disk you want to
2929
// have access to in the built Go binary.
3030
type Box struct {
31-
Path string `json:"path"`
32-
Name string `json:"name"`
33-
ResolutionDir string `json:"resolution_dir"`
34-
DefaultResolver resolver.Resolver `json:"default_resolver"`
35-
resolvers resolversMap
36-
dirs dirsMap
31+
Path string `json:"path"`
32+
Name string `json:"name"`
33+
ResolutionDir string `json:"resolution_dir"`
34+
DefaultResolver resolver.Resolver `json:"default_resolver"`
35+
resolvers resolversMap
36+
dirs dirsMap
3737
}
3838

3939
// NewBox returns a Box that can be used to
@@ -215,7 +215,12 @@ func (b *Box) Resolve(key string) (file.File, error) {
215215

216216
f, err := r.Resolve(b.Name, key)
217217
if err != nil {
218-
z := filepath.Join(resolver.OsPath(b.ResolutionDir), filepath.FromSlash(path.Clean("/"+resolver.OsPath(key))))
218+
z, err := resolver.ResolvePathInBase(resolver.OsPath(b.ResolutionDir), filepath.FromSlash(path.Clean("/"+resolver.OsPath(key))))
219+
if err != nil {
220+
plog.Debug(r, "Resolve", "box", b.Name, "key", key, "err", err)
221+
return f, err
222+
}
223+
219224
f, err = r.Resolve(b.Name, z)
220225
if err != nil {
221226
plog.Debug(r, "Resolve", "box", b.Name, "key", z, "err", err)

v2/box_test.go

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,9 @@ func Test_Box_Open(t *testing.T) {
182182
r := require.New(t)
183183

184184
d := resolver.NewInMemory(map[string]file.File{
185-
"foo.txt": qfile("foo.txt", "foo!"),
186-
"bar": qfile("bar", "bar!"),
187-
"baz/index.html": qfile("baz", "baz!"),
185+
"foo.txt": qfile("foo.txt", "foo!"),
186+
"bar": qfile("bar", "bar!"),
187+
"baz/index.html": qfile("baz", "baz!"),
188188
})
189189
box := New("Test_Box_Open", "./templates")
190190

@@ -223,3 +223,31 @@ func Test_Box_HasDir(t *testing.T) {
223223
r.True(box.HasDir("c"))
224224
r.False(box.HasDir("a"))
225225
}
226+
227+
func Test_Box_Traversal_Standard(t *testing.T) {
228+
r := require.New(t)
229+
box := New("Test_Box_Traversal_Standard", "")
230+
_, err := box.FindString("../go.mod")
231+
r.Error(err)
232+
}
233+
234+
func Test_Box_Traversal_Standard_Depth2(t *testing.T) {
235+
r := require.New(t)
236+
box := New("Test_Box_Traversal_Standard_Depth2", "")
237+
_, err := box.FindString("../../packr/go.mod")
238+
r.Error(err)
239+
}
240+
241+
func Test_Box_Traversal_Backslash(t *testing.T) {
242+
r := require.New(t)
243+
box := New("Test_Box_Traversal_Backslash", "")
244+
_, err := box.FindString("..\\go.mod")
245+
r.Error(err)
246+
}
247+
248+
func Test_Box_Traversal_Backslash_Depth2(t *testing.T) {
249+
r := require.New(t)
250+
box := New("Test_Box_Traversal_Backslash_Depth2", "")
251+
_, err := box.FindString("..\\..packr2\\go.mod")
252+
r.Error(err)
253+
}

v2/file/resolver/disk.go

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,15 @@ func (d Disk) String() string {
2323
}
2424

2525
func (d *Disk) Resolve(box string, name string) (file.File, error) {
26+
var err error
2627
path := OsPath(name)
2728
if !filepath.IsAbs(path) {
28-
path = filepath.Join(OsPath(d.Root), path)
29+
path, err = ResolvePathInBase(OsPath(d.Root), path)
30+
if err != nil {
31+
return nil, err
32+
}
2933
}
34+
3035
fi, err := os.Stat(path)
3136
if err != nil {
3237
return nil, err
@@ -40,6 +45,32 @@ func (d *Disk) Resolve(box string, name string) (file.File, error) {
4045
return nil, os.ErrNotExist
4146
}
4247

48+
// resolvePathInBase returns a path that is guaranteed to be inside of the base directory or an error
49+
func ResolvePathInBase(base string, path string) (string, error) {
50+
// Determine the absolute file path of the base directory
51+
d, err := filepath.Abs(base)
52+
if err != nil {
53+
return "", err
54+
}
55+
56+
// Return the base directory if no file was requested
57+
if path == "/" || path == "\\" {
58+
return d, nil
59+
}
60+
61+
// Resolve the absolute file path after combining the key with base
62+
p, err := filepath.Abs(filepath.Join(d, path))
63+
if err != nil {
64+
return "", err
65+
}
66+
67+
// Verify that the resolved path is inside of the base directory
68+
if !strings.HasPrefix(p, d+string(filepath.Separator)) {
69+
return "", os.ErrNotExist
70+
}
71+
return p, nil
72+
}
73+
4374
var _ file.FileMappable = &Disk{}
4475

4576
func (d *Disk) FileMap() map[string]file.File {
@@ -70,8 +101,8 @@ func (d *Disk) FileMap() map[string]file.File {
70101
return nil
71102
}
72103
err := godirwalk.Walk(root, &godirwalk.Options{
73-
FollowSymbolicLinks: true,
74-
Callback: callback,
104+
FollowSymbolicLinks: true,
105+
Callback: callback,
75106
})
76107
if err != nil {
77108
plog.Logger.Errorf("[%s] error walking %v", root, err)

0 commit comments

Comments
 (0)