Merge pull request #1042 from ramiresviana/fixes-2
This commit is contained in:
		
						commit
						14e2f84ceb
					
				| 
						 | 
					@ -16,4 +16,5 @@ var (
 | 
				
			||||||
	ErrInvalidAuthMethod    = errors.New("invalid auth method")
 | 
						ErrInvalidAuthMethod    = errors.New("invalid auth method")
 | 
				
			||||||
	ErrPermissionDenied     = errors.New("permission denied")
 | 
						ErrPermissionDenied     = errors.New("permission denied")
 | 
				
			||||||
	ErrInvalidRequestParams = errors.New("invalid request params")
 | 
						ErrInvalidRequestParams = errors.New("invalid request params")
 | 
				
			||||||
 | 
						ErrSourceIsParent       = errors.New("source is parent")
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,7 +43,7 @@ async function resourceAction (url, method, content) {
 | 
				
			||||||
  const res = await fetchURL(`/api/resources${url}`, opts)
 | 
					  const res = await fetchURL(`/api/resources${url}`, opts)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (res.status !== 200) {
 | 
					  if (res.status !== 200) {
 | 
				
			||||||
    throw new Error(res.responseText)
 | 
					    throw new Error(await res.text())
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    return res
 | 
					    return res
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,9 +8,7 @@
 | 
				
			||||||
    <input style="display:none" type="file" id="upload-folder-input" @change="uploadInput($event)" webkitdirectory multiple>
 | 
					    <input style="display:none" type="file" id="upload-folder-input" @change="uploadInput($event)" webkitdirectory multiple>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
  <div v-else id="listing"
 | 
					  <div v-else id="listing"
 | 
				
			||||||
    :class="user.viewMode"
 | 
					    :class="user.viewMode">
 | 
				
			||||||
    @dragenter="dragEnter"
 | 
					 | 
				
			||||||
    @dragend="dragEnd">
 | 
					 | 
				
			||||||
    <div>
 | 
					    <div>
 | 
				
			||||||
      <div class="item header">
 | 
					      <div class="item header">
 | 
				
			||||||
        <div></div>
 | 
					        <div></div>
 | 
				
			||||||
| 
						 | 
					@ -99,7 +97,8 @@ export default {
 | 
				
			||||||
  components: { Item },
 | 
					  components: { Item },
 | 
				
			||||||
  data: function () {
 | 
					  data: function () {
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      showLimit: 50
 | 
					      showLimit: 50,
 | 
				
			||||||
 | 
					      dragCounter: 0
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  computed: {
 | 
					  computed: {
 | 
				
			||||||
| 
						 | 
					@ -171,6 +170,8 @@ export default {
 | 
				
			||||||
    window.addEventListener('resize', this.resizeEvent)
 | 
					    window.addEventListener('resize', this.resizeEvent)
 | 
				
			||||||
    window.addEventListener('scroll', this.scrollEvent)
 | 
					    window.addEventListener('scroll', this.scrollEvent)
 | 
				
			||||||
    document.addEventListener('dragover', this.preventDefault)
 | 
					    document.addEventListener('dragover', this.preventDefault)
 | 
				
			||||||
 | 
					    document.addEventListener('dragenter', this.dragEnter)
 | 
				
			||||||
 | 
					    document.addEventListener('dragleave', this.dragLeave)
 | 
				
			||||||
    document.addEventListener('drop', this.drop)
 | 
					    document.addEventListener('drop', this.drop)
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  beforeDestroy () {
 | 
					  beforeDestroy () {
 | 
				
			||||||
| 
						 | 
					@ -179,6 +180,8 @@ export default {
 | 
				
			||||||
    window.removeEventListener('resize', this.resizeEvent)
 | 
					    window.removeEventListener('resize', this.resizeEvent)
 | 
				
			||||||
    window.removeEventListener('scroll', this.scrollEvent)
 | 
					    window.removeEventListener('scroll', this.scrollEvent)
 | 
				
			||||||
    document.removeEventListener('dragover', this.preventDefault)
 | 
					    document.removeEventListener('dragover', this.preventDefault)
 | 
				
			||||||
 | 
					    document.removeEventListener('dragenter', this.dragEnter)
 | 
				
			||||||
 | 
					    document.removeEventListener('dragleave', this.dragLeave)
 | 
				
			||||||
    document.removeEventListener('drop', this.drop)
 | 
					    document.removeEventListener('drop', this.drop)
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  methods: {
 | 
					  methods: {
 | 
				
			||||||
| 
						 | 
					@ -326,6 +329,8 @@ export default {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    dragEnter () {
 | 
					    dragEnter () {
 | 
				
			||||||
 | 
					      this.dragCounter++
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // When the user starts dragging an item, put every
 | 
					      // When the user starts dragging an item, put every
 | 
				
			||||||
      // file on the listing with 50% opacity.
 | 
					      // file on the listing with 50% opacity.
 | 
				
			||||||
      let items = document.getElementsByClassName('item')
 | 
					      let items = document.getElementsByClassName('item')
 | 
				
			||||||
| 
						 | 
					@ -334,11 +339,16 @@ export default {
 | 
				
			||||||
        file.style.opacity = 0.5
 | 
					        file.style.opacity = 0.5
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    dragEnd () {
 | 
					    dragLeave () {
 | 
				
			||||||
      this.resetOpacity()
 | 
					      this.dragCounter--
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (this.dragCounter == 0) {
 | 
				
			||||||
 | 
					        this.resetOpacity()
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    drop: async function (event) {
 | 
					    drop: async function (event) {
 | 
				
			||||||
      event.preventDefault()
 | 
					      event.preventDefault()
 | 
				
			||||||
 | 
					      this.dragCounter = 0
 | 
				
			||||||
      this.resetOpacity()
 | 
					      this.resetOpacity()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      let dt = event.dataTransfer
 | 
					      let dt = event.dataTransfer
 | 
				
			||||||
| 
						 | 
					@ -408,12 +418,13 @@ export default {
 | 
				
			||||||
          confirm: (event) => {
 | 
					          confirm: (event) => {
 | 
				
			||||||
            event.preventDefault()
 | 
					            event.preventDefault()
 | 
				
			||||||
            this.$store.commit('closeHovers')
 | 
					            this.$store.commit('closeHovers')
 | 
				
			||||||
            this.handleFiles(files, path, true)
 | 
					            upload.handleFiles(files, path, true)
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      upload.handleFiles(files, path)
 | 
					      upload.handleFiles(files, path)
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    resetOpacity () {
 | 
					    resetOpacity () {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,9 +27,11 @@ export default {
 | 
				
			||||||
  name: 'upload',
 | 
					  name: 'upload',
 | 
				
			||||||
  methods: {
 | 
					  methods: {
 | 
				
			||||||
    uploadFile: function () {
 | 
					    uploadFile: function () {
 | 
				
			||||||
 | 
					      document.getElementById('upload-input').value = ''
 | 
				
			||||||
      document.getElementById('upload-input').click()
 | 
					      document.getElementById('upload-input').click()
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    uploadFolder: function () {
 | 
					    uploadFolder: function () {
 | 
				
			||||||
 | 
					      document.getElementById('upload-folder-input').value = ''
 | 
				
			||||||
      document.getElementById('upload-folder-input').click()
 | 
					      document.getElementById('upload-folder-input').click()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,6 +10,8 @@ import (
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/spf13/afero"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/filebrowser/filebrowser/v2/errors"
 | 
						"github.com/filebrowser/filebrowser/v2/errors"
 | 
				
			||||||
	"github.com/filebrowser/filebrowser/v2/files"
 | 
						"github.com/filebrowser/filebrowser/v2/files"
 | 
				
			||||||
	"github.com/filebrowser/filebrowser/v2/fileutils"
 | 
						"github.com/filebrowser/filebrowser/v2/fileutils"
 | 
				
			||||||
| 
						 | 
					@ -139,38 +141,25 @@ var resourcePatchHandler = withUser(func(w http.ResponseWriter, r *http.Request,
 | 
				
			||||||
	dst := r.URL.Query().Get("destination")
 | 
						dst := r.URL.Query().Get("destination")
 | 
				
			||||||
	action := r.URL.Query().Get("action")
 | 
						action := r.URL.Query().Get("action")
 | 
				
			||||||
	dst, err := url.QueryUnescape(dst)
 | 
						dst, err := url.QueryUnescape(dst)
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errToStatus(err), err
 | 
							return errToStatus(err), err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if dst == "/" || src == "/" {
 | 
						if dst == "/" || src == "/" {
 | 
				
			||||||
		return http.StatusForbidden, nil
 | 
							return http.StatusForbidden, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if err = checkParent(src, dst); err != nil {
 | 
				
			||||||
 | 
							return http.StatusBadRequest, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	override := r.URL.Query().Get("override") == "true"
 | 
						override := r.URL.Query().Get("override") == "true"
 | 
				
			||||||
	rename := r.URL.Query().Get("rename") == "true"
 | 
						rename := r.URL.Query().Get("rename") == "true"
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !override && !rename {
 | 
						if !override && !rename {
 | 
				
			||||||
		if _, err = d.user.Fs.Stat(dst); err == nil {
 | 
							if _, err = d.user.Fs.Stat(dst); err == nil {
 | 
				
			||||||
			return http.StatusConflict, nil
 | 
								return http.StatusConflict, nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if rename {
 | 
						if rename {
 | 
				
			||||||
		counter := 1
 | 
							dst = addVersionSuffix(dst, d.user.Fs)
 | 
				
			||||||
		dir, name := filepath.Split(dst)
 | 
					 | 
				
			||||||
		ext := filepath.Ext(name)
 | 
					 | 
				
			||||||
		base := strings.TrimSuffix(name, ext)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for {
 | 
					 | 
				
			||||||
			if _, err = d.user.Fs.Stat(dst); err != nil {
 | 
					 | 
				
			||||||
				break
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			new := fmt.Sprintf("%s(%d)%s", base, counter, ext)
 | 
					 | 
				
			||||||
			dst = filepath.Join(dir, new)
 | 
					 | 
				
			||||||
			counter++
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = d.RunHook(func() error {
 | 
						err = d.RunHook(func() error {
 | 
				
			||||||
| 
						 | 
					@ -180,11 +169,14 @@ var resourcePatchHandler = withUser(func(w http.ResponseWriter, r *http.Request,
 | 
				
			||||||
			if !d.user.Perm.Create {
 | 
								if !d.user.Perm.Create {
 | 
				
			||||||
				return errors.ErrPermissionDenied
 | 
									return errors.ErrPermissionDenied
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			return fileutils.Copy(d.user.Fs, src, dst)
 | 
								return fileutils.Copy(d.user.Fs, src, dst)
 | 
				
			||||||
		case "rename":
 | 
							case "rename":
 | 
				
			||||||
			if !d.user.Perm.Rename {
 | 
								if !d.user.Perm.Rename {
 | 
				
			||||||
				return errors.ErrPermissionDenied
 | 
									return errors.ErrPermissionDenied
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								dst = filepath.Clean("/" + dst)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			return d.user.Fs.Rename(src, dst)
 | 
								return d.user.Fs.Rename(src, dst)
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			return fmt.Errorf("unsupported action %s: %w", action, errors.ErrInvalidRequestParams)
 | 
								return fmt.Errorf("unsupported action %s: %w", action, errors.ErrInvalidRequestParams)
 | 
				
			||||||
| 
						 | 
					@ -193,3 +185,35 @@ var resourcePatchHandler = withUser(func(w http.ResponseWriter, r *http.Request,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return errToStatus(err), err
 | 
						return errToStatus(err), err
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func checkParent(src, dst string) error {
 | 
				
			||||||
 | 
						rel, err := filepath.Rel(src, dst)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rel = filepath.ToSlash(rel)
 | 
				
			||||||
 | 
						if !strings.HasPrefix(rel, "../") && rel != ".." && rel != "." {
 | 
				
			||||||
 | 
							return errors.ErrSourceIsParent
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func addVersionSuffix(path string, fs afero.Fs) string {
 | 
				
			||||||
 | 
						counter := 1
 | 
				
			||||||
 | 
						dir, name := filepath.Split(path)
 | 
				
			||||||
 | 
						ext := filepath.Ext(name)
 | 
				
			||||||
 | 
						base := strings.TrimSuffix(name, ext)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							if _, err := fs.Stat(path); err != nil {
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							renamed := fmt.Sprintf("%s(%d)%s", base, counter, ext)
 | 
				
			||||||
 | 
							path = filepath.ToSlash(dir) + renamed
 | 
				
			||||||
 | 
							counter++
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return path
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue