From 5eeb74af3f8ae7937bd49256c3cd16ad71a6dcd4 Mon Sep 17 00:00:00 2001 From: Oleg Lobanov Date: Mon, 28 Dec 2020 17:20:21 +0100 Subject: [PATCH] fix: limit user access to shared dir --- frontend/src/views/Share.vue | 30 ++++------------------------- http/public.go | 37 ++++++++++++++++++++++++------------ 2 files changed, 29 insertions(+), 38 deletions(-) diff --git a/frontend/src/views/Share.vue b/frontend/src/views/Share.vue index a08a6ef4..eea2b5d5 100644 --- a/frontend/src/views/Share.vue +++ b/frontend/src/views/Share.vue @@ -101,7 +101,7 @@ export default { }, data: () => ({ error: null, - filePath: '', + path: '', showLimit: 500 }), watch: { @@ -128,28 +128,8 @@ export default { if (this.req.type === 'video') return 'movie' return 'insert_drive_file' }, - path: function () { - let absoluteParts = this.filePath.split('/') - let urlParts = this.$route.params.pathMatch.split('/') - - absoluteParts.shift() - - absoluteParts.forEach((_, i) => absoluteParts[i] = encodeURIComponent(absoluteParts[i])) - urlParts.forEach((_, i) => urlParts[i] = encodeURIComponent(urlParts[i])) - - if (absoluteParts[absoluteParts.length - 1] === '') absoluteParts.pop() - if (urlParts[urlParts.length - 1] === '') urlParts.pop() - - if (urlParts.length === 1) return absoluteParts[absoluteParts.length - 1] - - let len = Math.min(absoluteParts.length, urlParts.length) - for (let i = 0; i < len; i++) { - if (urlParts[urlParts.length - 1 - i] !== absoluteParts[absoluteParts.length - 1 - i]) return urlParts.slice(urlParts.length - i).join('/') - } - return absoluteParts.slice(absoluteParts.length - len).join('/') - }, link: function () { - return `${baseURL}/api/public/dl/${this.hash}/${this.path}` + return `${baseURL}/api/public/dl/${this.hash}${this.path}` }, fullLink: function () { return window.location.origin + this.link @@ -185,8 +165,6 @@ export default { } } - breadcrumbs.shift() - if (breadcrumbs.length > 3) { while (breadcrumbs.length !== 4) { breadcrumbs.shift() @@ -216,10 +194,10 @@ export default { try { let file = await api.getHash(encodeURIComponent(this.$route.params.pathMatch)) - this.filePath = file.path + this.path = file.path if (file.isDir) file.items = file.items.map((item, index) => { item.index = index - item.url = `/share/${this.hash}/${this.path}/${encodeURIComponent(item.name)}` + item.url = `/share/${this.hash}${this.path}/${encodeURIComponent(item.name)}` return item }) this.updateRequest(file) diff --git a/http/public.go b/http/public.go index 79a68151..0ab5d952 100644 --- a/http/public.go +++ b/http/public.go @@ -2,25 +2,23 @@ package http import ( "net/http" + "path" "path/filepath" "strings" - libErrors "github.com/filebrowser/filebrowser/v2/errors" + "github.com/spf13/afero" + "github.com/filebrowser/filebrowser/v2/files" ) var withHashFile = func(fn handleFunc) handleFunc { return func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { - id, rootName, path := ifPathWithName(r) + id, path := ifPathWithName(r) link, err := d.store.Share.GetByHash(id) if err != nil { return errToStatus(err), err } - if rootName != "" && filepath.Base(rootName) != filepath.Base(link.Path) { - return errToStatus(libErrors.ErrNotExist), libErrors.ErrNotExist - } - user, err := d.store.Users.Get(d.server.Root, link.UserID) if err != nil { return errToStatus(err), err @@ -30,7 +28,7 @@ var withHashFile = func(fn handleFunc) handleFunc { file, err := files.NewFileInfo(files.FileOptions{ Fs: d.user.Fs, - Path: filepath.Join(link.Path, path), + Path: link.Path, Modify: d.user.Perm.Modify, Expand: true, Checker: d, @@ -39,6 +37,22 @@ var withHashFile = func(fn handleFunc) handleFunc { return errToStatus(err), err } + if file.IsDir { + // set fs root to the shared folder + d.user.Fs = afero.NewBasePathFs(d.user.Fs, filepath.Dir(link.Path)) + + file, err = files.NewFileInfo(files.FileOptions{ + Fs: d.user.Fs, + Path: path, + Modify: d.user.Perm.Modify, + Expand: true, + Checker: d, + }) + if err != nil { + return errToStatus(err), err + } + } + d.raw = file return fn(w, r, d) } @@ -46,17 +60,16 @@ var withHashFile = func(fn handleFunc) handleFunc { // ref to https://github.com/filebrowser/filebrowser/pull/727 // `/api/public/dl/MEEuZK-v/file-name.txt` for old browsers to save file with correct name -func ifPathWithName(r *http.Request) (id, rootName, path string) { +func ifPathWithName(r *http.Request) (id, filePath string) { pathElements := strings.Split(r.URL.Path, "/") // prevent maliciously constructed parameters like `/api/public/dl/XZzCDnK2_not_exists_hash_name` // len(pathElements) will be 1, and golang will panic `runtime error: index out of range` + switch len(pathElements) { case 1: - return r.URL.Path, "", "" - case 2: //nolint: mnd - return pathElements[0], pathElements[1], "" + return r.URL.Path, "/" default: - return pathElements[0], pathElements[1], strings.Join(pathElements[2:], "/") + return pathElements[0], path.Join("/", path.Join(pathElements[1:]...)) } }