mirror of
				https://github.com/mickael-kerjean/filestash.git
				synced 2025-10-31 18:16:00 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			163 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			163 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package plg_backend_tmp
 | |
| 
 | |
| import (
 | |
| 	"encoding/base64"
 | |
| 	"fmt"
 | |
| 	. "github.com/mickael-kerjean/filestash/server/common"
 | |
| 	"io"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"regexp"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	FILESTASH_DIRECTORY = "/tmp/filestash_tmp/"
 | |
| 	EMPTY_DOCX          = "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"
 | |
| )
 | |
| 
 | |
| var ChrootCache AppCache
 | |
| 
 | |
| func init() {
 | |
| 	Backend.Register("tmp", TmpStorage{})
 | |
| 	ChrootCache = NewAppCache(60 * 24 * 30)
 | |
| 	ChrootCache.OnEvict(func(key string, value interface{}) {
 | |
| 		chroot := value.(string)
 | |
| 		if strings.HasPrefix(chroot, FILESTASH_DIRECTORY) {
 | |
| 			os.RemoveAll(chroot)
 | |
| 		}
 | |
| 	})
 | |
| 	os.RemoveAll(FILESTASH_DIRECTORY)
 | |
| }
 | |
| 
 | |
| type TmpStorage struct{}
 | |
| 
 | |
| func (this TmpStorage) Init(params map[string]string, app *App) (IBackend, error) {
 | |
| 	if len(params["userID"]) == 0 {
 | |
| 		return nil, ErrAuthenticationFailed
 | |
| 	} else if regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(params["userID"]) == false {
 | |
| 		return nil, ErrAuthenticationFailed
 | |
| 	}
 | |
| 	p := filepath.Join(FILESTASH_DIRECTORY, params["userID"])
 | |
| 	if strings.HasSuffix(p, "/") == false {
 | |
| 		p = fmt.Sprintf("%s/", p)
 | |
| 	}
 | |
| 	if err := this.VerifyPath(p); err != nil {
 | |
| 		return nil, ErrAuthenticationFailed
 | |
| 	}
 | |
| 	if c := ChrootCache.Get(params); c == nil {
 | |
| 		ChrootCache.Set(params, p)
 | |
| 	}
 | |
| 	os.MkdirAll(p, 0755)
 | |
| 	params["path"] = p
 | |
| 	return &TmpStorage{}, nil
 | |
| }
 | |
| 
 | |
| func (this TmpStorage) LoginForm() Form {
 | |
| 	return Form{
 | |
| 		Elmnts: []FormElement{
 | |
| 			{
 | |
| 				Name:  "type",
 | |
| 				Type:  "hidden",
 | |
| 				Value: "tmp",
 | |
| 			},
 | |
| 			{
 | |
| 				Name:        "userID",
 | |
| 				Type:        "text",
 | |
| 				Placeholder: "user ID",
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (this TmpStorage) Ls(path string) ([]os.FileInfo, error) {
 | |
| 	if err := this.VerifyPath(path); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	f, err := SafeOsOpenFile(path, os.O_RDONLY, os.ModePerm)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return f.Readdir(-1)
 | |
| }
 | |
| 
 | |
| func (this TmpStorage) Cat(path string) (io.ReadCloser, error) {
 | |
| 	if err := this.VerifyPath(path); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	reader, err := SafeOsOpenFile(path, os.O_RDONLY, os.ModePerm)
 | |
| 	if err == nil {
 | |
| 		return reader, nil
 | |
| 	}
 | |
| 
 | |
| 	if os.IsExist(err) == false {
 | |
| 		if strings.HasSuffix(path, ".doc") || strings.HasSuffix(path, ".docx") {
 | |
| 			docx, err := base64.StdEncoding.DecodeString(EMPTY_DOCX)
 | |
| 			if err != nil {
 | |
| 				return nil, err
 | |
| 			}
 | |
| 			return NewReadCloserFromBytes(docx), nil
 | |
| 		}
 | |
| 		return NewReadCloserFromBytes([]byte("")), nil
 | |
| 	}
 | |
| 	return reader, err
 | |
| }
 | |
| 
 | |
| func (this TmpStorage) Mkdir(path string) error {
 | |
| 	if err := this.VerifyPath(path); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	return SafeOsMkdir(path, 0755)
 | |
| }
 | |
| 
 | |
| func (this TmpStorage) Rm(path string) error {
 | |
| 	if err := this.VerifyPath(path); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	return SafeOsRemoveAll(path)
 | |
| }
 | |
| 
 | |
| func (this TmpStorage) Mv(from, to string) error {
 | |
| 	if err := this.VerifyPath(from); err != nil {
 | |
| 		return err
 | |
| 	} else if err = this.VerifyPath(to); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	return SafeOsRename(from, to)
 | |
| }
 | |
| 
 | |
| func (this TmpStorage) Save(path string, content io.Reader) error {
 | |
| 	if err := this.VerifyPath(path); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	f, err := SafeOsOpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	_, err = io.Copy(f, content)
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| func (this TmpStorage) Touch(path string) error {
 | |
| 	if err := this.VerifyPath(path); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	f, err := SafeOsOpenFile(path, os.O_WRONLY|os.O_CREATE, os.ModePerm)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	if _, err = f.Write([]byte("")); err != nil {
 | |
| 		f.Close()
 | |
| 		return err
 | |
| 	}
 | |
| 	return f.Close()
 | |
| }
 | |
| 
 | |
| func (this TmpStorage) VerifyPath(path string) error {
 | |
| 	if strings.HasPrefix(path, FILESTASH_DIRECTORY) == false {
 | |
| 		Log.Warning("plg_backend_tmp::chroot attempt to circumvent chroot via path[%s]", path)
 | |
| 		return ErrPermissionDenied
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | 
