2022-06-10 06:38:29 +00:00
|
|
|
package archetype
|
|
|
|
|
|
|
|
import (
|
2022-06-13 06:32:14 +00:00
|
|
|
"errors"
|
2022-06-10 06:38:29 +00:00
|
|
|
"io/ioutil"
|
2022-06-13 06:32:14 +00:00
|
|
|
"net/http"
|
2022-06-12 06:00:38 +00:00
|
|
|
"os"
|
2022-06-10 06:38:29 +00:00
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
type SimpleFileManager struct {
|
2022-06-15 07:33:56 +00:00
|
|
|
Root string
|
|
|
|
ShowHTML bool
|
|
|
|
ShowHidden bool
|
|
|
|
maxUploadMB int64
|
2022-06-10 06:38:29 +00:00
|
|
|
}
|
|
|
|
|
2022-06-12 06:00:38 +00:00
|
|
|
type FileData struct {
|
2022-06-16 03:41:06 +00:00
|
|
|
Error string
|
|
|
|
Path string
|
|
|
|
Name string
|
|
|
|
Parent string
|
|
|
|
IsDir bool
|
2022-06-12 06:00:38 +00:00
|
|
|
}
|
|
|
|
|
2022-06-10 06:38:29 +00:00
|
|
|
type FileListing struct {
|
|
|
|
Error string
|
|
|
|
Root string
|
|
|
|
Up string
|
|
|
|
SubDirs []string
|
|
|
|
Files []string
|
|
|
|
}
|
|
|
|
|
|
|
|
type FileManager interface {
|
|
|
|
Init(cfg *Config) error
|
|
|
|
ListSubTree(root string) FileListing
|
2022-06-12 06:00:38 +00:00
|
|
|
GetFileData(slug string) FileData
|
2022-06-13 06:32:14 +00:00
|
|
|
AddFile(path string, req *http.Request) error
|
2022-06-14 04:03:34 +00:00
|
|
|
MkDir(path, newDir string) error
|
2022-06-13 06:32:14 +00:00
|
|
|
Remove(path string) error
|
2022-06-15 07:33:56 +00:00
|
|
|
Rename(oldFullPath, newPath, newName string) error
|
|
|
|
MaxUploadMB() int64
|
2022-06-10 06:38:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (self *SimpleFileManager) Init(cfg *Config) error {
|
2022-06-12 06:00:38 +00:00
|
|
|
self.Root = filepath.Clean(cfg.StaticRoot)
|
2022-06-15 07:33:56 +00:00
|
|
|
self.ShowHTML = cfg.StaticShowHTML
|
2022-06-10 06:38:29 +00:00
|
|
|
self.ShowHidden = cfg.StaticShowHidden
|
2022-06-15 07:33:56 +00:00
|
|
|
self.maxUploadMB = cfg.StaticMaxUploadMB
|
2022-06-10 06:38:29 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *SimpleFileManager) ListSubTree(root string) FileListing {
|
|
|
|
list := FileListing{}
|
|
|
|
|
2024-05-03 02:46:59 +00:00
|
|
|
fullPath := filepath.Join(self.Root, root)
|
|
|
|
|
|
|
|
if !strings.HasPrefix(filepath.Clean(fullPath), self.Root) {
|
2022-06-10 06:38:29 +00:00
|
|
|
list.Error = "You cannot escape!"
|
|
|
|
return list
|
|
|
|
}
|
|
|
|
|
|
|
|
files, err := ioutil.ReadDir(fullPath)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
list.Error = err.Error()
|
|
|
|
return list
|
|
|
|
}
|
|
|
|
|
|
|
|
list.Root = root
|
|
|
|
if !strings.HasSuffix(list.Root, "/") {
|
|
|
|
list.Root += "/"
|
|
|
|
}
|
|
|
|
if !strings.HasPrefix(list.Root, "/") {
|
|
|
|
list.Root = "/" + list.Root
|
|
|
|
}
|
|
|
|
|
|
|
|
levels := strings.Split(root, "/")
|
2022-06-16 03:41:06 +00:00
|
|
|
|
2022-06-10 06:38:29 +00:00
|
|
|
if list.Root != "/" {
|
|
|
|
list.Up = "/"
|
|
|
|
}
|
2022-06-16 03:41:06 +00:00
|
|
|
if len(levels) >= 2 && list.Root != "/" {
|
2022-06-15 07:33:56 +00:00
|
|
|
list.Up = strings.Join(levels[:len(levels)-1], "/")
|
|
|
|
if !strings.HasPrefix(list.Up, "/") {
|
|
|
|
list.Up = "/" + list.Up
|
|
|
|
}
|
2022-06-10 06:38:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, file := range files {
|
|
|
|
if !self.ShowHidden && strings.HasPrefix(file.Name(), ".") {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if file.IsDir() {
|
|
|
|
list.SubDirs = append(list.SubDirs, file.Name())
|
|
|
|
} else {
|
2022-06-15 07:33:56 +00:00
|
|
|
if !self.ShowHTML && strings.HasSuffix(file.Name(), ".html") {
|
2022-06-10 06:38:29 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
list.Files = append(list.Files, file.Name())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return list
|
|
|
|
}
|
2022-06-12 06:00:38 +00:00
|
|
|
|
|
|
|
func (self *SimpleFileManager) GetFileData(slug string) FileData {
|
|
|
|
fullPath := filepath.Join(self.Root, slug)
|
|
|
|
fileInfo, err := os.Stat(fullPath)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return FileData{
|
|
|
|
Error: err.Error(),
|
|
|
|
}
|
|
|
|
}
|
2024-05-03 02:46:59 +00:00
|
|
|
if !strings.HasPrefix(filepath.Clean(fullPath), self.Root) {
|
2022-06-12 06:00:38 +00:00
|
|
|
return FileData{
|
|
|
|
Error: "You cannot escape!",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanedSlug := filepath.Clean(slug)
|
|
|
|
fileBase := filepath.Base(cleanedSlug)
|
2022-06-16 03:41:06 +00:00
|
|
|
parent := strings.TrimSuffix("/"+cleanedSlug, "/"+fileBase)
|
2022-06-12 06:00:38 +00:00
|
|
|
return FileData{
|
2022-06-16 03:41:06 +00:00
|
|
|
Path: filepath.Clean(slug),
|
|
|
|
Name: fileBase,
|
|
|
|
Parent: parent,
|
|
|
|
IsDir: fileInfo.IsDir(),
|
2022-06-12 06:00:38 +00:00
|
|
|
}
|
|
|
|
}
|
2022-06-13 06:32:14 +00:00
|
|
|
|
|
|
|
func (self *SimpleFileManager) Remove(slug string) error {
|
|
|
|
fullPath := filepath.Join(self.Root, slug)
|
|
|
|
|
2024-05-03 02:46:59 +00:00
|
|
|
if !strings.HasPrefix(filepath.Clean(fullPath), self.Root) {
|
|
|
|
return errors.New("You cannot escape!")
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err := os.Stat(fullPath)
|
2022-06-13 06:32:14 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return os.RemoveAll(fullPath)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *SimpleFileManager) AddFile(path string, req *http.Request) error {
|
|
|
|
fullPath := filepath.Join(self.Root, path)
|
2024-05-03 02:46:59 +00:00
|
|
|
|
|
|
|
if !strings.HasPrefix(filepath.Clean(fullPath), filepath.Clean(self.Root)) {
|
|
|
|
return errors.New("You cannot escape!")
|
|
|
|
}
|
|
|
|
|
2022-06-13 06:32:14 +00:00
|
|
|
_, err := os.Stat(fullPath)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-06-15 07:33:56 +00:00
|
|
|
req.ParseMultipartForm(self.maxUploadMB << 20)
|
2022-06-13 06:32:14 +00:00
|
|
|
file, header, err := req.FormFile("file")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
fileData, err := ioutil.ReadAll(file)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
destPath := filepath.Join(fullPath, header.Filename)
|
|
|
|
dest, err := os.Create(destPath)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer dest.Close()
|
|
|
|
|
|
|
|
dest.Write(fileData)
|
|
|
|
return nil
|
|
|
|
}
|
2022-06-14 04:03:34 +00:00
|
|
|
|
|
|
|
func (self *SimpleFileManager) MkDir(path, newDir string) error {
|
|
|
|
fullPath := filepath.Join(self.Root, path)
|
2024-05-03 02:46:59 +00:00
|
|
|
if !strings.HasPrefix(filepath.Clean(fullPath), self.Root) {
|
2022-06-14 04:03:34 +00:00
|
|
|
return errors.New("You cannot escape!")
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err := os.Stat(fullPath)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if strings.Contains(newDir, "/") || strings.Contains(newDir, "\\") {
|
|
|
|
return errors.New("Cannot create nested directories at once")
|
|
|
|
}
|
|
|
|
|
|
|
|
newDirPath := filepath.Join(fullPath, newDir)
|
|
|
|
_, err = os.Stat(newDirPath)
|
|
|
|
if !os.IsNotExist(err) {
|
|
|
|
return errors.New("Directory exists")
|
|
|
|
}
|
|
|
|
|
|
|
|
return os.Mkdir(newDirPath, 0755)
|
|
|
|
}
|
2022-06-15 07:33:56 +00:00
|
|
|
|
|
|
|
func (self *SimpleFileManager) Rename(oldFullPath, newPath, newName string) error {
|
|
|
|
fullPath := filepath.Join(self.Root, oldFullPath)
|
2024-05-03 02:46:59 +00:00
|
|
|
|
|
|
|
if !strings.HasPrefix(filepath.Clean(fullPath), self.Root) {
|
|
|
|
return errors.New("You cannot escape!")
|
|
|
|
}
|
|
|
|
|
2022-06-15 07:33:56 +00:00
|
|
|
_, err := os.Stat(fullPath)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2024-05-03 02:46:59 +00:00
|
|
|
newParent := filepath.Clean(filepath.Join(self.Root, newPath))
|
|
|
|
if !strings.HasPrefix(newParent, self.Root) {
|
|
|
|
return errors.New("You cannot escape!")
|
|
|
|
}
|
|
|
|
|
2022-06-15 07:33:56 +00:00
|
|
|
_, err = os.Stat(newParent)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if newName == "" {
|
|
|
|
_, oldName := filepath.Split(oldFullPath)
|
|
|
|
newName = oldName
|
|
|
|
}
|
|
|
|
|
2024-05-03 02:46:59 +00:00
|
|
|
newFullPath := filepath.Join(newParent, newName)
|
|
|
|
if !strings.HasPrefix(filepath.Clean(newFullPath), newParent) {
|
|
|
|
return errors.New("You cannot escape!")
|
|
|
|
}
|
|
|
|
|
2022-06-15 07:33:56 +00:00
|
|
|
return os.Rename(fullPath, filepath.Join(newParent, newName))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *SimpleFileManager) MaxUploadMB() int64 {
|
|
|
|
return self.maxUploadMB
|
|
|
|
}
|