feat: some more updates
License: MIT Signed-off-by: Henrique Dias <hacdias@gmail.com>
This commit is contained in:
parent
40b4e2e678
commit
0133b7e73e
@ -38,22 +38,31 @@ type FileInfo struct {
|
||||
Checksums map[string]string `json:"checksums,omitempty"`
|
||||
}
|
||||
|
||||
// FileOptions are the options when getting a file info.
|
||||
type FileOptions struct {
|
||||
Fs afero.Fs
|
||||
Path string
|
||||
Modify bool
|
||||
Expand bool
|
||||
Checker rules.Checker
|
||||
}
|
||||
|
||||
// NewFileInfo creates a File object from a path and a given user. This File
|
||||
// object will be automatically filled depending on if it is a directory
|
||||
// or a file. If it's a video file, it will also detect any subtitles.
|
||||
func NewFileInfo(fs afero.Fs, path string, modify bool, checker rules.Checker) (*FileInfo, error) {
|
||||
if !checker.Check(path) {
|
||||
func NewFileInfo(opts FileOptions) (*FileInfo, error) {
|
||||
if !opts.Checker.Check(opts.Path) {
|
||||
return nil, os.ErrPermission
|
||||
}
|
||||
|
||||
info, err := fs.Stat(path)
|
||||
info, err := opts.Fs.Stat(opts.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
file := &FileInfo{
|
||||
Fs: fs,
|
||||
Path: path,
|
||||
Fs: opts.Fs,
|
||||
Path: opts.Path,
|
||||
Name: info.Name(),
|
||||
ModTime: info.ModTime(),
|
||||
Mode: info.Mode(),
|
||||
@ -62,13 +71,15 @@ func NewFileInfo(fs afero.Fs, path string, modify bool, checker rules.Checker) (
|
||||
Extension: filepath.Ext(info.Name()),
|
||||
}
|
||||
|
||||
if file.IsDir {
|
||||
return file, file.readListing(checker)
|
||||
}
|
||||
if opts.Expand {
|
||||
if file.IsDir {
|
||||
return file, file.readListing(opts.Checker)
|
||||
}
|
||||
|
||||
err = file.detectType(modify)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
err = file.detectType(opts.Modify)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return file, err
|
||||
|
||||
2
frontend
2
frontend
@ -1 +1 @@
|
||||
Subproject commit a71029771582dbc85baa5a4eb984d800311b01c5
|
||||
Subproject commit a53f11bb786b409a1320866113276acbddbf97ac
|
||||
@ -39,7 +39,7 @@ func NewHandler(storage *storage.Storage) (http.Handler, error) {
|
||||
api.PathPrefix("/resources").Handler(handle(resourcePostPutHandler, "/api/resources", storage)).Methods("PUT")
|
||||
api.PathPrefix("/resources").Handler(handle(resourcePatchHandler, "/api/resources", storage)).Methods("PATCH")
|
||||
|
||||
api.PathPrefix("/share").Handler(handle(shareGetHandler, "/api/share", storage)).Methods("GET")
|
||||
api.PathPrefix("/share").Handler(handle(shareGetsHandler, "/api/share", storage)).Methods("GET")
|
||||
api.PathPrefix("/share").Handler(handle(sharePostHandler, "/api/share", storage)).Methods("POST")
|
||||
api.PathPrefix("/share").Handler(handle(shareDeleteHandler, "/api/share", storage)).Methods("DELETE")
|
||||
|
||||
@ -50,7 +50,9 @@ func NewHandler(storage *storage.Storage) (http.Handler, error) {
|
||||
api.PathPrefix("/command").Handler(handle(commandsHandler, "/api/command", storage)).Methods("GET")
|
||||
api.PathPrefix("/search").Handler(handle(searchHandler, "/api/search", storage)).Methods("GET")
|
||||
|
||||
public := api.PathPrefix("/public").Subrouter()
|
||||
public.PathPrefix("/dl").Handler(handle(publicDlHandler, "/api/public/dl/", storage)).Methods("GET")
|
||||
public.PathPrefix("/share").Handler(handle(publicShareHandler, "/api/public/share/", storage)).Methods("GET")
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
|
||||
|
||||
50
http/public.go
Normal file
50
http/public.go
Normal file
@ -0,0 +1,50 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/filebrowser/filebrowser/files"
|
||||
)
|
||||
|
||||
var withHashFile = func(fn handleFunc) handleFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
||||
link, err := d.store.Share.GetByHash(r.URL.Path)
|
||||
if err != nil {
|
||||
return errToStatus(err), err
|
||||
}
|
||||
|
||||
user, err := d.store.Users.Get(link.UserID)
|
||||
if err != nil {
|
||||
return errToStatus(err), err
|
||||
}
|
||||
|
||||
d.user = user
|
||||
|
||||
file, err := files.NewFileInfo(files.FileOptions{
|
||||
Fs: d.user.Fs,
|
||||
Path: link.Path,
|
||||
Modify: d.user.Perm.Modify,
|
||||
Expand: false,
|
||||
Checker: d,
|
||||
})
|
||||
if err != nil {
|
||||
return errToStatus(err), err
|
||||
}
|
||||
|
||||
d.raw = file
|
||||
return fn(w, r, d)
|
||||
}
|
||||
}
|
||||
|
||||
var publicShareHandler = withHashFile(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
||||
return renderJSON(w, r, d.raw)
|
||||
})
|
||||
|
||||
var publicDlHandler = withHashFile(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
||||
file := d.raw.(*files.FileInfo)
|
||||
if !file.IsDir {
|
||||
return rawFileHandler(w, r, file)
|
||||
}
|
||||
|
||||
return rawDirHandler(w, r, d, file)
|
||||
})
|
||||
15
http/raw.go
15
http/raw.go
@ -2,6 +2,7 @@ package http
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
@ -60,7 +61,13 @@ var rawHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data)
|
||||
return http.StatusAccepted, nil
|
||||
}
|
||||
|
||||
file, err := files.NewFileInfo(d.user.Fs, r.URL.Path, d.user.Perm.Modify, d)
|
||||
file, err := files.NewFileInfo(files.FileOptions{
|
||||
Fs: d.user.Fs,
|
||||
Path: r.URL.Path,
|
||||
Modify: d.user.Perm.Modify,
|
||||
Expand: false,
|
||||
Checker: d,
|
||||
})
|
||||
if err != nil {
|
||||
return errToStatus(err), err
|
||||
}
|
||||
@ -73,6 +80,9 @@ var rawHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data)
|
||||
})
|
||||
|
||||
func addFile(ar archiver.Writer, d *data, path string) error {
|
||||
// Checks are always done with paths with "/" as path separator.
|
||||
path = strings.Replace(path, "\\", "/", -1)
|
||||
fmt.Println(path)
|
||||
if !d.Check(path) {
|
||||
return nil
|
||||
}
|
||||
@ -82,7 +92,6 @@ func addFile(ar archiver.Writer, d *data, path string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// open the file
|
||||
file, err := d.user.Fs.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -92,7 +101,7 @@ func addFile(ar archiver.Writer, d *data, path string) error {
|
||||
err = ar.Write(archiver.File{
|
||||
FileInfo: archiver.FileInfo{
|
||||
FileInfo: info,
|
||||
CustomName: path,
|
||||
CustomName: strings.TrimPrefix(path, "/"),
|
||||
},
|
||||
ReadCloser: file,
|
||||
})
|
||||
|
||||
@ -16,7 +16,13 @@ import (
|
||||
)
|
||||
|
||||
var resourceGetHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
||||
file, err := files.NewFileInfo(d.user.Fs, r.URL.Path, d.user.Perm.Modify, d)
|
||||
file, err := files.NewFileInfo(files.FileOptions{
|
||||
Fs: d.user.Fs,
|
||||
Path: r.URL.Path,
|
||||
Modify: d.user.Perm.Modify,
|
||||
Expand: true,
|
||||
Checker: d,
|
||||
})
|
||||
if err != nil {
|
||||
return errToStatus(err), err
|
||||
}
|
||||
|
||||
@ -22,8 +22,8 @@ func withPermShare(fn handleFunc) handleFunc {
|
||||
})
|
||||
}
|
||||
|
||||
var shareGetHandler = withPermShare(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
||||
s, err := d.store.Share.Gets(r.URL.Path)
|
||||
var shareGetsHandler = withPermShare(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
||||
s, err := d.store.Share.Gets(r.URL.Path, d.user.ID)
|
||||
if err == errors.ErrNotExist {
|
||||
return renderJSON(w, r, []*share.Link{})
|
||||
}
|
||||
@ -32,13 +32,6 @@ var shareGetHandler = withPermShare(func(w http.ResponseWriter, r *http.Request,
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
for i, link := range s {
|
||||
if link.Expires && link.ExpireDate.Before(time.Now()) {
|
||||
d.store.Share.Delete(link.Hash)
|
||||
s = append(s[:i], s[i+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
return renderJSON(w, r, s)
|
||||
})
|
||||
|
||||
@ -56,12 +49,12 @@ var shareDeleteHandler = withPermShare(func(w http.ResponseWriter, r *http.Reque
|
||||
|
||||
var sharePostHandler = withPermShare(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
||||
var s *share.Link
|
||||
expire := r.URL.Query().Get("expires")
|
||||
rawExpire := r.URL.Query().Get("expires")
|
||||
unit := r.URL.Query().Get("unit")
|
||||
|
||||
if expire == "" {
|
||||
if rawExpire == "" {
|
||||
var err error
|
||||
s, err = d.store.Share.GetPermanent(r.URL.Path)
|
||||
s, err = d.store.Share.GetPermanent(r.URL.Path, d.user.ID)
|
||||
if err == nil {
|
||||
w.Write([]byte(d.settings.BaseURL + "/share/" + s.Hash))
|
||||
return 0, nil
|
||||
@ -76,14 +69,10 @@ var sharePostHandler = withPermShare(func(w http.ResponseWriter, r *http.Request
|
||||
|
||||
str := base64.URLEncoding.EncodeToString(bytes)
|
||||
|
||||
s = &share.Link{
|
||||
Path: r.URL.Path,
|
||||
Hash: str,
|
||||
Expires: expire != "",
|
||||
}
|
||||
var expire int64 = 0
|
||||
|
||||
if expire != "" {
|
||||
num, err := strconv.Atoi(expire)
|
||||
if rawExpire != "" {
|
||||
num, err := strconv.Atoi(rawExpire)
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
@ -100,7 +89,14 @@ var sharePostHandler = withPermShare(func(w http.ResponseWriter, r *http.Request
|
||||
add = time.Hour * time.Duration(num)
|
||||
}
|
||||
|
||||
s.ExpireDate = time.Now().Add(add)
|
||||
expire = time.Now().Add(add).Unix()
|
||||
}
|
||||
|
||||
s = &share.Link{
|
||||
Path: r.URL.Path,
|
||||
Hash: str,
|
||||
Expire: expire,
|
||||
UserID: d.user.ID,
|
||||
}
|
||||
|
||||
if err := d.store.Share.Save(s); err != nil {
|
||||
|
||||
@ -4,6 +4,8 @@ import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/filebrowser/filebrowser/errors"
|
||||
)
|
||||
|
||||
func renderJSON(w http.ResponseWriter, r *http.Request, data interface{}) (int, error) {
|
||||
@ -27,9 +29,9 @@ func errToStatus(err error) int {
|
||||
return http.StatusOK
|
||||
case os.IsPermission(err):
|
||||
return http.StatusForbidden
|
||||
case os.IsNotExist(err):
|
||||
case os.IsNotExist(err), err == errors.ErrNotExist:
|
||||
return http.StatusNotFound
|
||||
case os.IsExist(err):
|
||||
case os.IsExist(err), err == errors.ErrExist:
|
||||
return http.StatusConflict
|
||||
default:
|
||||
return http.StatusInternalServerError
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
package share
|
||||
|
||||
import "time"
|
||||
|
||||
// Link is the information needed to build a shareable link.
|
||||
type Link struct {
|
||||
Hash string `json:"hash" storm:"id,index"`
|
||||
Path string `json:"path" storm:"index"`
|
||||
Expires bool `json:"expires"`
|
||||
ExpireDate time.Time `json:"expireDate"`
|
||||
Hash string `json:"hash" storm:"id,index"`
|
||||
Path string `json:"path" storm:"index"`
|
||||
UserID uint `json:"userID"`
|
||||
Expire int64 `json:"expire"`
|
||||
}
|
||||
|
||||
@ -1,10 +1,16 @@
|
||||
package share
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/filebrowser/filebrowser/errors"
|
||||
)
|
||||
|
||||
// StorageBackend is the interface to implement for a share storage.
|
||||
type StorageBackend interface {
|
||||
GetByHash(hash string) (*Link, error)
|
||||
GetPermanent(path string) (*Link, error)
|
||||
Gets(path string) ([]*Link, error)
|
||||
GetPermanent(path string, id uint) (*Link, error)
|
||||
Gets(path string, id uint) ([]*Link, error)
|
||||
Save(s *Link) error
|
||||
Delete(hash string) error
|
||||
}
|
||||
@ -21,17 +27,40 @@ func NewStorage(back StorageBackend) *Storage {
|
||||
|
||||
// GetByHash wraps a StorageBackend.GetByHash.
|
||||
func (s *Storage) GetByHash(hash string) (*Link, error) {
|
||||
return s.back.GetByHash(hash)
|
||||
link, err := s.back.GetByHash(hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if link.Expire != 0 && link.Expire <= time.Now().Unix() {
|
||||
s.Delete(link.Hash)
|
||||
return nil, errors.ErrNotExist
|
||||
}
|
||||
|
||||
return link, nil
|
||||
}
|
||||
|
||||
// GetPermanent wraps a StorageBackend.GetPermanent
|
||||
func (s *Storage) GetPermanent(path string) (*Link, error) {
|
||||
return s.back.GetPermanent(path)
|
||||
func (s *Storage) GetPermanent(path string, id uint) (*Link, error) {
|
||||
return s.back.GetPermanent(path, id)
|
||||
}
|
||||
|
||||
// Gets wraps a StorageBackend.Gets
|
||||
func (s *Storage) Gets(path string) ([]*Link, error) {
|
||||
return s.back.Gets(path)
|
||||
func (s *Storage) Gets(path string, id uint) ([]*Link, error) {
|
||||
links, err := s.back.Gets(path, id)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i, link := range links {
|
||||
if link.Expire != 0 && link.Expire <= time.Now().Unix() {
|
||||
s.Delete(link.Hash)
|
||||
links = append(links[:i], links[i+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
return links, nil
|
||||
}
|
||||
|
||||
// Save wraps a StorageBackend.Save
|
||||
|
||||
@ -21,9 +21,9 @@ func (s shareBackend) GetByHash(hash string) (*share.Link, error) {
|
||||
return &v, err
|
||||
}
|
||||
|
||||
func (s shareBackend) GetPermanent(path string) (*share.Link, error) {
|
||||
func (s shareBackend) GetPermanent(path string, id uint) (*share.Link, error) {
|
||||
var v share.Link
|
||||
err := s.db.Select(q.Eq("Path", path), q.Eq("Expires", false)).First(&v)
|
||||
err := s.db.Select(q.Eq("Path", path), q.Eq("Expire", 0), q.Eq("UserID", id)).First(&v)
|
||||
if err == storm.ErrNotFound {
|
||||
return nil, errors.ErrNotExist
|
||||
}
|
||||
@ -31,9 +31,9 @@ func (s shareBackend) GetPermanent(path string) (*share.Link, error) {
|
||||
return &v, err
|
||||
}
|
||||
|
||||
func (s shareBackend) Gets(hash string) ([]*share.Link, error) {
|
||||
func (s shareBackend) Gets(path string, id uint) ([]*share.Link, error) {
|
||||
var v []*share.Link
|
||||
err := s.db.Find("Path", hash, &v)
|
||||
err := s.db.Select(q.Eq("Path", path), q.Eq("UserID", id)).Find(&v)
|
||||
if err == storm.ErrNotFound {
|
||||
return v, errors.ErrNotExist
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user