mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-27 22:23:48 +03:00
fileserver: Improve file hiding logic for directories and prefixes
Now, a filename to hide that is specified without a path separator will count as hidden if it appears in any component of the file path (not only the last component); semantically, this means hiding a file by only its name (without any part of a path) will hide both files and folders, e.g. hiding ".git" will hide "/.git" and also "/.git/foo". We also do prefix matching so that hiding "/.git" will hide "/.git" and "/.git/foo" but not "/.gitignore". The remaining logic is a globular match like before.
This commit is contained in:
parent
9859ab8148
commit
0ee4378227
2 changed files with 95 additions and 17 deletions
|
@ -329,28 +329,37 @@ func sanitizedPathJoin(root, reqPath string) string {
|
|||
// fileHidden returns true if filename is hidden
|
||||
// according to the hide list.
|
||||
func fileHidden(filename string, hide []string) bool {
|
||||
nameOnly := filepath.Base(filename)
|
||||
sep := string(filepath.Separator)
|
||||
var components []string
|
||||
|
||||
for _, h := range hide {
|
||||
// assuming h is a glob/shell-like pattern,
|
||||
// use it to compare the whole file path;
|
||||
// but if there is no separator in h, then
|
||||
// just compare against the file's name
|
||||
compare := filename
|
||||
if !strings.Contains(h, sep) {
|
||||
compare = nameOnly
|
||||
}
|
||||
|
||||
hidden, err := filepath.Match(h, compare)
|
||||
if err != nil {
|
||||
// malformed pattern; fallback by checking prefix
|
||||
if strings.HasPrefix(filename, h) {
|
||||
// if there is no separator in h, then we assume the user
|
||||
// wants to hide any files or folders that match that
|
||||
// name; thus we have to compare against each component
|
||||
// of the filename, e.g. hiding "bar" would hide "/bar"
|
||||
// as well as "/foo/bar/baz" but not "/barstool".
|
||||
if len(components) == 0 {
|
||||
components = strings.Split(filename, sep)
|
||||
}
|
||||
for _, c := range components {
|
||||
if c == h {
|
||||
return true
|
||||
}
|
||||
}
|
||||
} else if strings.HasPrefix(filename, h) {
|
||||
// otherwise, if there is a separator in h, and
|
||||
// filename is exactly prefixed with h, then we
|
||||
// can do a prefix match so that "/foo" matches
|
||||
// "/foo/bar" but not "/foobar".
|
||||
withoutPrefix := strings.TrimPrefix(filename, h)
|
||||
if strings.HasPrefix(withoutPrefix, sep) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if hidden {
|
||||
// file name or path matches hide pattern
|
||||
|
||||
// in the general case, a glob match will suffice
|
||||
if hidden, _ := filepath.Match(h, filename); hidden {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,9 +93,78 @@ func TestSanitizedPathJoin(t *testing.T) {
|
|||
}
|
||||
actual := sanitizedPathJoin(tc.inputRoot, u.Path)
|
||||
if actual != tc.expect {
|
||||
t.Errorf("Test %d: [%s %s] => %s (expected %s)", i, tc.inputRoot, tc.inputPath, actual, tc.expect)
|
||||
t.Errorf("Test %d: [%s %s] => %s (expected %s)",
|
||||
i, tc.inputRoot, tc.inputPath, actual, tc.expect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: test fileHidden
|
||||
func TestFileHidden(t *testing.T) {
|
||||
for i, tc := range []struct {
|
||||
inputHide []string
|
||||
inputPath string
|
||||
expect bool
|
||||
}{
|
||||
{
|
||||
inputHide: nil,
|
||||
inputPath: "",
|
||||
expect: false,
|
||||
},
|
||||
{
|
||||
inputHide: []string{".gitignore"},
|
||||
inputPath: "/.gitignore",
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
inputHide: []string{".git"},
|
||||
inputPath: "/.gitignore",
|
||||
expect: false,
|
||||
},
|
||||
{
|
||||
inputHide: []string{"/.git"},
|
||||
inputPath: "/.gitignore",
|
||||
expect: false,
|
||||
},
|
||||
{
|
||||
inputHide: []string{".git"},
|
||||
inputPath: "/.git",
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
inputHide: []string{".git"},
|
||||
inputPath: "/.git/foo",
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
inputHide: []string{".git"},
|
||||
inputPath: "/foo/.git/bar",
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
inputHide: []string{"/prefix"},
|
||||
inputPath: "/prefix/foo",
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
inputHide: []string{"/foo/*/bar"},
|
||||
inputPath: "/foo/asdf/bar",
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
inputHide: []string{"/foo"},
|
||||
inputPath: "/foo",
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
inputHide: []string{"/foo"},
|
||||
inputPath: "/foobar",
|
||||
expect: false,
|
||||
},
|
||||
} {
|
||||
actual := fileHidden(tc.inputPath, tc.inputHide)
|
||||
if actual != tc.expect {
|
||||
t.Errorf("Test %d: Is %s hidden in %v? Got %t but expected %t",
|
||||
i, tc.inputPath, tc.inputHide, actual, tc.expect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue