fileserver: Use EscapedPath for browse (#5534)

* fileserver: Use EscapedPath for browse

Fix #5143

* Fixes if filter element is not present

* Remove extraneous line
This commit is contained in:
Matt Holt 2023-05-15 10:48:05 -06:00 committed by GitHub
parent 96919acc9d
commit 52d7335c2b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 47 additions and 7 deletions

View file

@ -82,8 +82,8 @@ func (fsrv *FileServer) serveBrowse(root, dirPath string, w http.ResponseWriter,
repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer) repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
// calling path.Clean here prevents weird breadcrumbs when URL paths are sketchy like /%2e%2e%2f // TODO: not entirely sure if path.Clean() is necessary here but seems like a safe plan (i.e. /%2e%2e%2f) - someone could verify this
listing, err := fsrv.loadDirectoryContents(r.Context(), dir.(fs.ReadDirFile), root, path.Clean(r.URL.Path), repl) listing, err := fsrv.loadDirectoryContents(r.Context(), dir.(fs.ReadDirFile), root, path.Clean(r.URL.EscapedPath()), repl)
switch { switch {
case os.IsPermission(err): case os.IsPermission(err):
return caddyhttp.Error(http.StatusForbidden, err) return caddyhttp.Error(http.StatusForbidden, err)

View file

@ -850,11 +850,11 @@ footer {
<script> <script>
const filterEl = document.getElementById('filter'); const filterEl = document.getElementById('filter');
filterEl.focus({ preventScroll: true }); filterEl?.focus({ preventScroll: true });
function initPage() { function initPage() {
// populate and evaluate filter // populate and evaluate filter
if (!filterEl.value) { if (!filterEl?.value) {
const filterParam = new URL(window.location.href).searchParams.get('filter'); const filterParam = new URL(window.location.href).searchParams.get('filter');
if (filterParam) { if (filterParam) {
filterEl.value = filterParam; filterEl.value = filterParam;
@ -874,6 +874,7 @@ footer {
} }
function filter() { function filter() {
if (!filterEl) return;
const q = filterEl.value.trim().toLowerCase(); const q = filterEl.value.trim().toLowerCase();
document.querySelectorAll('tr.file').forEach(function(el) { document.querySelectorAll('tr.file').forEach(function(el) {
if (!q) { if (!q) {

View file

@ -25,6 +25,45 @@ func TestBreadcrumbs(t *testing.T) {
}{ }{
{"", []crumb{}}, {"", []crumb{}},
{"/", []crumb{{Text: "/"}}}, {"/", []crumb{{Text: "/"}}},
{"/foo/", []crumb{
{Link: "../", Text: "/"},
{Link: "", Text: "foo"},
}},
{"/foo/bar/", []crumb{
{Link: "../../", Text: "/"},
{Link: "../", Text: "foo"},
{Link: "", Text: "bar"},
}},
{"/foo bar/", []crumb{
{Link: "../", Text: "/"},
{Link: "", Text: "foo bar"},
}},
{"/foo bar/baz/", []crumb{
{Link: "../../", Text: "/"},
{Link: "../", Text: "foo bar"},
{Link: "", Text: "baz"},
}},
{"/100%25 test coverage/is a lie/", []crumb{
{Link: "../../", Text: "/"},
{Link: "../", Text: "100% test coverage"},
{Link: "", Text: "is a lie"},
}},
{"/AC%2FDC/", []crumb{
{Link: "../", Text: "/"},
{Link: "", Text: "AC/DC"},
}},
{"/foo/%2e%2e%2f/bar", []crumb{
{Link: "../../../", Text: "/"},
{Link: "../../", Text: "foo"},
{Link: "../", Text: "../"},
{Link: "", Text: "bar"},
}},
{"/foo/../bar", []crumb{
{Link: "../../../", Text: "/"},
{Link: "../../", Text: "foo"},
{Link: "../", Text: ".."},
{Link: "", Text: "bar"},
}},
{"foo/bar/baz", []crumb{ {"foo/bar/baz", []crumb{
{Link: "../../", Text: "foo"}, {Link: "../../", Text: "foo"},
{Link: "../", Text: "bar"}, {Link: "../", Text: "bar"},
@ -51,16 +90,16 @@ func TestBreadcrumbs(t *testing.T) {
}}, }},
} }
for _, d := range testdata { for testNum, d := range testdata {
l := browseTemplateContext{Path: d.path} l := browseTemplateContext{Path: d.path}
actual := l.Breadcrumbs() actual := l.Breadcrumbs()
if len(actual) != len(d.expected) { if len(actual) != len(d.expected) {
t.Errorf("wrong size output, got %d elements but expected %d", len(actual), len(d.expected)) t.Errorf("Test %d: Got %d components but expected %d; got: %+v", testNum, len(actual), len(d.expected), actual)
continue continue
} }
for i, c := range actual { for i, c := range actual {
if c != d.expected[i] { if c != d.expected[i] {
t.Errorf("got %#v but expected %#v at index %d", c, d.expected[i], i) t.Errorf("Test %d crumb %d: got %#v but expected %#v at index %d", testNum, i, c, d.expected[i], i)
} }
} }
} }