cleanup and bug fixing

License: MIT
Signed-off-by: Henrique Dias <hacdias@gmail.com>
This commit is contained in:
Henrique Dias 2019-01-04 21:46:53 +00:00
parent 9f58170575
commit ff99e72093
28 changed files with 458 additions and 410 deletions

View File

@ -20,14 +20,15 @@ var cmdsAddCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
db := getDB()
defer db.Close()
st := getFileBrowser(db)
s := st.GetSettings()
st := getStorage(db)
s, err := st.Settings.Get()
checkErr(err)
evt := mustGetString(cmd, "event")
command := mustGetString(cmd, "command")
s.Commands[evt] = append(s.Commands[evt], command)
err := st.SaveSettings(s)
err = st.Settings.Save(s)
checkErr(err)
printEvents(s.Commands)
},

View File

@ -17,8 +17,9 @@ var cmdsLsCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
db := getDB()
defer db.Close()
st := getFileBrowser(db)
s := st.GetSettings()
st := getStorage(db)
s, err := st.Settings.Get()
checkErr(err)
evt := mustGetString(cmd, "event")
if evt == "" {

View File

@ -20,15 +20,16 @@ var cmdsRmCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
db := getDB()
defer db.Close()
st := getFileBrowser(db)
s := st.GetSettings()
st := getStorage(db)
s, err := st.Settings.Get()
checkErr(err)
evt := mustGetString(cmd, "event")
i, err := cmd.Flags().GetUint("index")
checkErr(err)
s.Commands[evt] = append(s.Commands[evt][:i], s.Commands[evt][i+1:]...)
err = st.SaveSettings(s)
err = st.Settings.Save(s)
checkErr(err)
printEvents(s.Commands)
},

View File

@ -2,14 +2,15 @@ package cmd
import (
"encoding/json"
"errors"
nerrors "errors"
"fmt"
"os"
"strings"
"text/tabwriter"
"github.com/filebrowser/filebrowser/auth"
"github.com/filebrowser/filebrowser/settings"
"github.com/filebrowser/filebrowser/errors"
"github.com/spf13/cobra"
)
@ -46,14 +47,14 @@ func addConfigFlags(cmd *cobra.Command) {
cmd.Flags().Bool("branding.disableExternal", false, "disable external links such as GitHub links")
}
func getAuthentication(cmd *cobra.Command) (lib.AuthMethod, lib.Auther) {
method := lib.AuthMethod(mustGetString(cmd, "auth.method"))
func getAuthentication(cmd *cobra.Command) (settings.AuthMethod, auth.Auther) {
method := settings.AuthMethod(mustGetString(cmd, "auth.method"))
var auther lib.Auther
var auther auth.Auther
if method == auth.MethodProxyAuth {
header := mustGetString(cmd, "auth.header")
if header == "" {
panic(errors.New("you must set the flag 'auth.header' for method 'proxy'"))
panic(nerrors.New("you must set the flag 'auth.header' for method 'proxy'"))
}
auther = &auth.ProxyAuth{Header: header}
}
@ -81,13 +82,13 @@ func getAuthentication(cmd *cobra.Command) (lib.AuthMethod, lib.Auther) {
}
if auther == nil {
panic(lib.ErrInvalidAuthMethod)
panic(errors.ErrInvalidAuthMethod)
}
return method, auther
}
func printSettings(s *lib.Settings, auther lib.Auther) {
func printSettings(s *settings.Settings, auther auth.Auther) {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
fmt.Fprintf(w, "\nBase URL:\t%s\n", s.BaseURL)

View File

@ -16,9 +16,10 @@ var configCatCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
db := getDB()
defer db.Close()
st := getFileBrowser(db)
s := st.GetSettings()
auther, err := st.GetAuther(s.AuthMethod)
st := getStorage(db)
s, err := st.Settings.Get()
checkErr(err)
auther, err := st.Auth.Get(s.AuthMethod)
checkErr(err)
printSettings(s, auther)
},

View File

@ -7,7 +7,7 @@ import (
"strings"
"github.com/asdine/storm"
"github.com/filebrowser/filebrowser/settings"
"github.com/spf13/cobra"
)
@ -32,30 +32,31 @@ override the options.`,
panic(errors.New(databasePath + " already exists"))
}
defaults := lib.UserDefaults{}
defaults := settings.UserDefaults{}
getUserDefaults(cmd, &defaults, true)
authMethod, auther := getAuthentication(cmd)
db, err := storm.Open(databasePath)
checkErr(err)
defer db.Close()
st := getFileBrowser(db)
settings := st.GetSettings()
st := getStorage(db)
s, err := st.Settings.Get()
checkErr(err)
settings.BaseURL = mustGetString(cmd, "baseURL")
settings.Signup = mustGetBool(cmd, "signup")
settings.Shell = strings.Split(strings.TrimSpace(mustGetString(cmd, "shell")), " ")
settings.Defaults = defaults
settings.AuthMethod = authMethod
settings.Branding = lib.Branding{
s.BaseURL = mustGetString(cmd, "baseURL")
s.Signup = mustGetBool(cmd, "signup")
s.Shell = strings.Split(strings.TrimSpace(mustGetString(cmd, "shell")), " ")
s.Defaults = defaults
s.AuthMethod = authMethod
s.Branding = settings.Branding{
Name: mustGetString(cmd, "branding.name"),
DisableExternal: mustGetBool(cmd, "branding.disableExternal"),
Files: mustGetString(cmd, "branding.files"),
}
err = st.SaveSettings(settings)
err = st.Settings.Save(s)
checkErr(err)
err = st.SaveAuther(auther)
err = st.Auth.Save(auther)
checkErr(err)
fmt.Printf(`
@ -63,6 +64,6 @@ Congratulations! You've set up your database to use with File Browser.
Now add your first user via 'filebrowser users new' and then you just
need to call the main command to boot up the server.
`)
printSettings(settings, auther)
printSettings(s, auther)
},
}

View File

@ -3,7 +3,7 @@ package cmd
import (
"strings"
"github.com/filebrowser/filebrowser/auth"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
@ -23,10 +23,11 @@ you want to change.`,
db := getDB()
defer db.Close()
st := getFileBrowser(db)
s := st.GetSettings()
st := getStorage(db)
s, err := st.Settings.Get()
checkErr(err)
auth := false
hasAuth := false
cmd.Flags().Visit(func(flag *pflag.Flag) {
switch flag.Name {
case "baseURL":
@ -34,7 +35,7 @@ you want to change.`,
case "signup":
s.Signup = mustGetBool(cmd, "signup")
case "auth.method":
auth = true
hasAuth = true
case "shell":
s.Shell = strings.Split(strings.TrimSpace(mustGetString(cmd, "shell")), " ")
case "branding.name":
@ -48,18 +49,17 @@ you want to change.`,
getUserDefaults(cmd, &s.Defaults, false)
var auther lib.Auther
var err error
if auth {
var auther auth.Auther
if hasAuth {
s.AuthMethod, auther = getAuthentication(cmd)
err = st.SaveAuther(auther)
err = st.Auth.Save(auther)
checkErr(err)
} else {
auther, err = st.GetAuther(s.AuthMethod)
auther, err = st.Auth.Get(s.AuthMethod)
checkErr(err)
}
err = st.SaveSettings(s)
err = st.Settings.Save(s)
checkErr(err)
printSettings(s, auther)
},

View File

@ -1,6 +1,7 @@
package cmd
import (
"crypto/rand"
"crypto/tls"
"errors"
"io/ioutil"
@ -12,7 +13,8 @@ import (
"github.com/asdine/storm"
"github.com/filebrowser/filebrowser/auth"
"github.com/filebrowser/filebrowser/settings"
"github.com/filebrowser/filebrowser/users"
fbhttp "github.com/filebrowser/filebrowser/http"
"github.com/spf13/cobra"
@ -56,9 +58,10 @@ listening on loalhost on a random port. Use the flags to change it.`,
var err error
db := getDB()
defer db.Close()
fb := getFileBrowser(db)
handler, err := fbhttp.NewHandler(fb)
st := getStorage(db)
handler, err := fbhttp.NewHandler(st)
checkErr(err)
startServer(cmd, handler)
},
@ -91,46 +94,48 @@ func quickSetup(cmd *cobra.Command) {
db, err := storm.Open(databasePath)
checkErr(err)
defer db.Close()
fb := getFileBrowser(db)
settings := fb.GetSettings()
settings.BaseURL = ""
settings.Signup = false
settings.AuthMethod = auth.MethodJSONAuth
settings.Defaults = lib.UserDefaults{
Scope: scope,
Locale: "en",
Perm: lib.Permissions{
Admin: false,
Execute: true,
Create: true,
Rename: true,
Modify: true,
Delete: true,
Share: true,
Download: true,
set := &settings.Settings{
BaseURL: "",
Signup: false,
AuthMethod: auth.MethodJSONAuth,
Defaults: settings.UserDefaults{
Scope: scope,
Locale: "en",
Perm: users.Permissions{
Admin: false,
Execute: true,
Create: true,
Rename: true,
Modify: true,
Delete: true,
Share: true,
Download: true,
},
},
}
err = fb.SaveSettings(settings)
checkErr(err)
err = fb.SaveAuther(&auth.JSONAuth{})
checkErr(err)
password, err := lib.HashPwd("admin")
st := getStorage(db)
err = st.Settings.Save(set)
checkErr(err)
user := &lib.User{
err = st.Auth.Save(&auth.JSONAuth{})
checkErr(err)
password, err := users.HashPwd("admin")
checkErr(err)
user := &users.User{
Username: "admin",
Password: password,
LockPassword: false,
}
fb.ApplyDefaults(user)
set.Defaults.Apply(user)
user.Perm.Admin = true
err = fb.SaveUser(user)
err = st.Users.Save(user)
checkErr(err)
}
@ -160,3 +165,11 @@ func startServer(cmd *cobra.Command, handler http.Handler) {
log.Fatal(err)
}
}
func generateRandomBytes(n int) []byte {
b := make([]byte, n)
_, err := rand.Read(b)
checkErr(err)
// Note that err == nil only if we read len(b) bytes.
return b
}

View File

@ -6,7 +6,8 @@ import (
"os"
"text/tabwriter"
"github.com/filebrowser/filebrowser/settings"
"github.com/filebrowser/filebrowser/users"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
@ -26,7 +27,7 @@ var usersCmd = &cobra.Command{
},
}
func printUsers(users []*lib.User) {
func printUsers(users []*users.User) {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
fmt.Fprintln(w, "ID\tUsername\tScope\tLocale\tV. Mode\tAdmin\tExecute\tCreate\tRename\tModify\tDelete\tShare\tDownload\tPwd Lock")
@ -78,18 +79,18 @@ func addUserFlags(cmd *cobra.Command) {
cmd.Flags().StringSlice("commands", nil, "a list of the commands a user can execute")
cmd.Flags().String("scope", "", "scope for users")
cmd.Flags().String("locale", "en", "locale for users")
cmd.Flags().String("viewMode", string(lib.ListViewMode), "view mode for users")
cmd.Flags().String("viewMode", string(users.ListViewMode), "view mode for users")
}
func getViewMode(cmd *cobra.Command) lib.ViewMode {
viewMode := lib.ViewMode(mustGetString(cmd, "viewMode"))
if viewMode != lib.ListViewMode && viewMode != lib.MosaicViewMode {
checkErr(errors.New("view mode must be \"" + string(lib.ListViewMode) + "\" or \"" + string(lib.MosaicViewMode) + "\""))
func getViewMode(cmd *cobra.Command) users.ViewMode {
viewMode := users.ViewMode(mustGetString(cmd, "viewMode"))
if viewMode != users.ListViewMode && viewMode != users.MosaicViewMode {
checkErr(errors.New("view mode must be \"" + string(users.ListViewMode) + "\" or \"" + string(users.MosaicViewMode) + "\""))
}
return viewMode
}
func getUserDefaults(cmd *cobra.Command, defaults *lib.UserDefaults, all bool) {
func getUserDefaults(cmd *cobra.Command, defaults *settings.UserDefaults, all bool) {
visit := func(flag *pflag.Flag) {
switch flag.Name {
case "scope":

View File

@ -1,7 +1,7 @@
package cmd
import (
"github.com/filebrowser/filebrowser/users"
"github.com/spf13/cobra"
)
@ -30,28 +30,28 @@ var usersLsCmd = &cobra.Command{
var findUsers = func(cmd *cobra.Command, args []string) {
db := getDB()
defer db.Close()
st := getFileBrowser(db)
st := getStorage(db)
username, _ := cmd.Flags().GetString("username")
id, _ := cmd.Flags().GetUint("id")
var err error
var users []*lib.User
var user *lib.User
var list []*users.User
var user *users.User
if username != "" {
user, err = st.GetUser(username)
user, err = st.Users.Get(username)
} else if id != 0 {
user, err = st.GetUser(id)
user, err = st.Users.Get(id)
} else {
users, err = st.GetUsers()
list, err = st.Users.Gets()
}
checkErr(err)
if user != nil {
users = []*lib.User{user}
list = []*users.User{user}
}
printUsers(users)
printUsers(list)
}

View File

@ -1,7 +1,7 @@
package cmd
import (
"github.com/filebrowser/filebrowser/users"
"github.com/spf13/cobra"
)
@ -23,24 +23,25 @@ var usersNewCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
db := getDB()
defer db.Close()
st := getFileBrowser(db)
st := getStorage(db)
settings := st.GetSettings()
getUserDefaults(cmd, &settings.Defaults, false)
s, err := st.Settings.Get()
checkErr(err)
getUserDefaults(cmd, &s.Defaults, false)
password, _ := cmd.Flags().GetString("password")
password, err := lib.HashPwd(password)
password, err = users.HashPwd(password)
checkErr(err)
user := &lib.User{
user := &users.User{
Username: mustGetString(cmd, "username"),
Password: password,
LockPassword: mustGetBool(cmd, "lockPassword"),
}
st.ApplyDefaults(user)
err = st.SaveUser(user)
s.Defaults.Apply(user)
err = st.Users.Save(user)
checkErr(err)
printUsers([]*lib.User{user})
printUsers([]*users.User{user})
},
}

View File

@ -20,7 +20,7 @@ var usersRmCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
db := getDB()
defer db.Close()
st := getFileBrowser(db)
st := getStorage(db)
username, _ := cmd.Flags().GetString("username")
id, _ := cmd.Flags().GetUint("id")
@ -28,9 +28,9 @@ var usersRmCmd = &cobra.Command{
var err error
if username != "" {
err = st.DeleteUser(username)
err = st.Users.Delete(username)
} else {
err = st.DeleteUser(id)
err = st.Users.Delete(id)
}
checkErr(err)

View File

@ -1,7 +1,8 @@
package cmd
import (
"github.com/filebrowser/filebrowser/settings"
"github.com/filebrowser/filebrowser/users"
"github.com/spf13/cobra"
)
@ -23,24 +24,24 @@ options you want to change.`,
Run: func(cmd *cobra.Command, args []string) {
db := getDB()
defer db.Close()
st := getFileBrowser(db)
st := getStorage(db)
id, _ := cmd.Flags().GetUint("id")
username := mustGetString(cmd, "username")
password := mustGetString(cmd, "password")
var user *lib.User
var user *users.User
var err error
if id != 0 {
user, err = st.GetUser(id)
user, err = st.Users.Get(id)
} else {
user, err = st.GetUser(username)
user, err = st.Users.Get(username)
}
checkErr(err)
defaults := lib.UserDefaults{
defaults := settings.UserDefaults{
Scope: user.Scope,
Locale: user.Locale,
ViewMode: user.ViewMode,
@ -62,12 +63,12 @@ options you want to change.`,
}
if password != "" {
user.Password, err = lib.HashPwd(password)
user.Password, err = users.HashPwd(password)
checkErr(err)
}
err = st.UpdateUser(user)
err = st.Users.Update(user)
checkErr(err)
printUsers([]*lib.User{user})
printUsers([]*users.User{user})
},
}

View File

@ -5,8 +5,8 @@ import (
"os"
"github.com/asdine/storm"
"github.com/filebrowser/filebrowser/bolt"
"github.com/filebrowser/filebrowser/storage"
"github.com/filebrowser/filebrowser/storage/bolt"
"github.com/spf13/cobra"
)
@ -38,8 +38,6 @@ func getDB() *storm.DB {
return db
}
func getFileBrowser(db *storm.DB) *lib.FileBrowser {
fb, err := lib.NewFileBrowser(&bolt.Backend{DB: db})
checkErr(err)
return fb
func getStorage(db *storm.DB) *storage.Storage {
return bolt.NewStorage(db)
}

View File

@ -3,7 +3,7 @@ package cmd
import (
"fmt"
"github.com/filebrowser/filebrowser/version"
"github.com/spf13/cobra"
)
@ -15,6 +15,6 @@ var versionCmd = &cobra.Command{
Use: "version",
Short: "Print the version number",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("File Browser Version " + lib.Version)
fmt.Println("File Browser Version " + version.Version)
},
}

View File

@ -3,14 +3,15 @@ package errors
import "errors"
var (
ErrEmptyKey = errors.New("empty key")
ErrExist = errors.New("the resource already exists")
ErrNotExist = errors.New("the resource does not exist")
ErrEmptyPassword = errors.New("password is empty")
ErrEmptyUsername = errors.New("username is empty")
ErrEmptyRequest = errors.New("empty request")
ErrScopeIsRelative = errors.New("scope is a relative path")
ErrInvalidDataType = errors.New("invalid data type")
ErrIsDirectory = errors.New("file is directory")
ErrInvalidOption = errors.New("invalid option")
ErrEmptyKey = errors.New("empty key")
ErrExist = errors.New("the resource already exists")
ErrNotExist = errors.New("the resource does not exist")
ErrEmptyPassword = errors.New("password is empty")
ErrEmptyUsername = errors.New("username is empty")
ErrEmptyRequest = errors.New("empty request")
ErrScopeIsRelative = errors.New("scope is a relative path")
ErrInvalidDataType = errors.New("invalid data type")
ErrIsDirectory = errors.New("file is directory")
ErrInvalidOption = errors.New("invalid option")
ErrInvalidAuthMethod = errors.New("invalid auth method")
)

View File

@ -15,10 +15,10 @@ type modifyRequest struct {
func NewHandler(storage *storage.Storage) (http.Handler, error) {
r := mux.NewRouter()
/* index, static := e.getStaticHandlers()
index, static := getStaticHandlers(storage)
r.PathPrefix("/static").Handler(static)
r.NotFoundHandler = index */
r.NotFoundHandler = index
api := r.PathPrefix("/api").Subrouter()
@ -26,12 +26,12 @@ func NewHandler(storage *storage.Storage) (http.Handler, error) {
api.Handle("/signup", handle(signupHandler, "", storage))
api.Handle("/renew", handle(renewHandler, "", storage))
/* users := api.PathPrefix("/users").Subrouter()
users.HandleFunc("", e.auth(e.usersGetHandler)).Methods("GET")
users.HandleFunc("", e.auth(e.userPostHandler)).Methods("POST")
users.HandleFunc("/{id:[0-9]+}", e.auth(e.userPutHandler)).Methods("PUT")
users.HandleFunc("/{id:[0-9]+}", e.auth(e.userGetHandler)).Methods("GET")
users.HandleFunc("/{id:[0-9]+}", e.auth(e.userDeleteHandler)).Methods("DELETE") */
users := api.PathPrefix("/users").Subrouter()
users.Handle("", handle(usersGetHandler, "", storage)).Methods("GET")
users.Handle("", handle(userPostHandler, "", storage)).Methods("POST")
users.Handle("/{id:[0-9]+}", handle(userPutHandler, "", storage)).Methods("PUT")
users.Handle("/{id:[0-9]+}", handle(userGetHandler, "", storage)).Methods("GET")
users.Handle("/{id:[0-9]+}", handle(userDeleteHandler, "", storage)).Methods("DELETE")
api.PathPrefix("/resources").Handler(handle(resourceGetHandler, "/api/resources", storage)).Methods("GET")
api.PathPrefix("/resources").Handler(handle(resourceDeleteHandler, "/api/resources", storage)).Methods("DELETE")
@ -46,8 +46,8 @@ func NewHandler(storage *storage.Storage) (http.Handler, error) {
api.Handle("/settings", handle(settingsGetHandler, "", storage)).Methods("GET")
api.Handle("/settings", handle(settingsPutHandler, "", storage)).Methods("PUT")
/* api.PathPrefix("/raw").HandlerFunc(e.auth(e.rawHandler)).Methods("GET")
api.PathPrefix("/command").HandlerFunc(e.auth(e.commandsHandler))
api.PathPrefix("/raw").Handler(handle(rawHandler, "/api/raw", storage)).Methods("GET")
/* api.PathPrefix("/command").HandlerFunc(e.auth(e.commandsHandler))
api.PathPrefix("/search").HandlerFunc(e.auth(e.searchHandler)) */
return r, nil

View File

@ -1,7 +1,17 @@
package http
/*
const apiRawPrefix = "/api/raw"
import (
"errors"
"net/http"
"net/url"
"path/filepath"
"strings"
"github.com/filebrowser/filebrowser/files"
"github.com/filebrowser/filebrowser/users"
"github.com/hacdias/fileutils"
"github.com/mholt/archiver"
)
func parseQueryFiles(r *http.Request, f *files.FileInfo, u *users.User) ([]string, error) {
files := []string{}
@ -45,38 +55,77 @@ func parseQueryAlgorithm(r *http.Request) (string, archiver.Writer, error) {
}
}
func (e *env) rawHandler(w http.ResponseWriter, r *http.Request) {
path, user, ok := e.getResourceData(w, r, apiRawPrefix)
if !ok {
return
var rawHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
if !d.user.Perm.Download {
return http.StatusAccepted, nil
}
if !user.Perm.Download {
httpErr(w, r, http.StatusForbidden, nil)
return
}
file, err := files.NewFileInfo(user.Fs, path, user.Perm.Modify)
file, err := files.NewFileInfo(d.user.Fs, r.URL.Path, d.user.Perm.Modify, d)
if err != nil {
httpErr(w, r, httpFsErr(err), err)
return
return errToStatus(err), err
}
if !file.IsDir {
fileHandler(w, r, file, user)
return
return rawFileHandler(w, r, file)
}
filenames, err := parseQueryFiles(r, file, user)
return rawDirHandler(w, r, d, file)
})
func addFile(ar archiver.Writer, d *data, path string) error {
if !d.Check(path) {
return nil
}
info, err := d.user.Fs.Stat(path)
if err != nil {
httpErr(w, r, http.StatusInternalServerError, err)
return
return err
}
// open the file
file, err := d.user.Fs.Open(path)
if err != nil {
return err
}
defer file.Close()
err = ar.Write(archiver.File{
FileInfo: archiver.FileInfo{
FileInfo: info,
CustomName: path,
},
ReadCloser: file,
})
if err != nil {
return err
}
if info.IsDir() {
names, err := file.Readdirnames(0)
if err != nil {
return err
}
for _, name := range names {
err = addFile(ar, d, filepath.Join(path, name))
if err != nil {
return err
}
}
}
return nil
}
func rawDirHandler(w http.ResponseWriter, r *http.Request, d *data, file *files.FileInfo) (int, error) {
filenames, err := parseQueryFiles(r, file, d.user)
if err != nil {
return http.StatusInternalServerError, err
}
extension, ar, err := parseQueryAlgorithm(r)
if err != nil {
httpErr(w, r, http.StatusInternalServerError, err)
return
return http.StatusInternalServerError, err
}
name := file.Name
@ -88,53 +137,24 @@ func (e *env) rawHandler(w http.ResponseWriter, r *http.Request) {
err = ar.Create(w)
if err != nil {
httpErr(w, r, http.StatusInternalServerError, err)
return
return http.StatusInternalServerError, err
}
defer ar.Close()
for _, fname := range filenames {
info, err := user.Fs.Stat(fname)
err = addFile(ar, d, fname)
if err != nil {
httpErr(w, r, http.StatusInternalServerError, err)
return
}
// get file's name for the inside of the archive
internalName, err := archiver.NameInArchive(info, fname, fname)
if err != nil {
httpErr(w, r, http.StatusInternalServerError, err)
return
}
// open the file
file, err := user.Fs.Open(fname)
if err != nil {
httpErr(w, r, http.StatusInternalServerError, err)
return
}
// write it to the archive
err = ar.Write(archiver.File{
FileInfo: archiver.FileInfo{
FileInfo: info,
CustomName: internalName,
},
ReadCloser: file,
})
file.Close()
if err != nil {
httpErr(w, r, http.StatusInternalServerError, err)
return
return http.StatusInternalServerError, err
}
}
return 0, nil
}
func fileHandler(w http.ResponseWriter, r *http.Request, file *files.File, user *users.User) {
fd, err := user.Fs.Open(file.Path)
func rawFileHandler(w http.ResponseWriter, r *http.Request, file *files.FileInfo) (int, error) {
fd, err := file.Fs.Open(file.Path)
if err != nil {
httpErr(w, r, http.StatusInternalServerError, err)
return
return http.StatusInternalServerError, err
}
defer fd.Close()
@ -146,4 +166,5 @@ func fileHandler(w http.ResponseWriter, r *http.Request, file *files.File, user
}
http.ServeContent(w, r, file.Name, file.ModTime, fd)
} */
return 0, nil
}

View File

@ -15,8 +15,6 @@ import (
"github.com/filebrowser/filebrowser/fileutils"
)
// TODO: trim path
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)
if err != nil {

View File

@ -1,40 +1,39 @@
package http
/*
import (
"encoding/json"
"text/template"
"log"
"net/http"
"os"
"path/filepath"
"strings"
"github.com/GeertJohan/go.rice"
"github.com/filebrowser/filebrowser/auth"
"github.com/filebrowser/filebrowser/storage"
"github.com/filebrowser/filebrowser/version"
)
func getStaticData(storage *storage.Storage) (map[string]interface{}, error) {
settings, err := storage.Settings.Get()
if err != nil {
return nil, err
}
func handleWithStaticData(w http.ResponseWriter, r *http.Request, d *data, box *rice.Box, file, contentType string) (int, error) {
w.Header().Set("Content-Type", contentType)
staticURL := strings.TrimPrefix(settings.BaseURL+"/static", "/")
staticURL := strings.TrimPrefix(d.settings.BaseURL+"/static", "/")
data := map[string]interface{}{
"Name": settings.Branding.Name,
"DisableExternal": settings.Branding.DisableExternal,
"BaseURL": settings.BaseURL,
"Name": d.settings.Branding.Name,
"DisableExternal": d.settings.Branding.DisableExternal,
"BaseURL": d.settings.BaseURL,
"Version": version.Version,
"StaticURL": staticURL,
"Signup": settings.Signup,
"NoAuth": settings.AuthMethod == auth.MethodNoAuth,
"Signup": d.settings.Signup,
"NoAuth": d.settings.AuthMethod == auth.MethodNoAuth,
"CSS": false,
"ReCaptcha": false,
}
if settings.Branding.Files != "" {
path := filepath.Join(settings.Branding.Files, "custom.css")
if d.settings.Branding.Files != "" {
path := filepath.Join(d.settings.Branding.Files, "custom.css")
_, err := os.Stat(path)
if err != nil && !os.IsNotExist(err) {
@ -46,10 +45,10 @@ func getStaticData(storage *storage.Storage) (map[string]interface{}, error) {
}
}
if settings.AuthMethod == auth.MethodJSONAuth {
raw, err := storage.Auth.Get()
if d.settings.AuthMethod == auth.MethodJSONAuth {
raw, err := d.store.Auth.Get(d.settings.AuthMethod)
if err != nil {
return nil, err
return http.StatusInternalServerError, err
}
auther := raw.(*auth.JSONAuth)
@ -61,68 +60,62 @@ func getStaticData(storage *storage.Storage) (map[string]interface{}, error) {
}
}
b, _ := json.MarshalIndent(data, "", " ")
b, err := json.MarshalIndent(data, "", " ")
if err != nil {
return http.StatusInternalServerError, err
}
data["Json"] = string(b)
return data, nil
index := template.Must(template.New("index").Delims("[{[", "]}]").Parse(box.MustString(file)))
err = index.Execute(w, data)
if err != nil {
return http.StatusInternalServerError, err
}
return 0, nil
}
func getStaticHandlers(storage *storage.Storage) (http.Handler, http.Handler, error) {
func getStaticHandlers(storage *storage.Storage) (http.Handler, http.Handler) {
box := rice.MustFindBox("../frontend/dist")
handler := http.FileServer(box.HTTPBox())
handleWithData := func(w http.ResponseWriter, r *http.Request, file string, contentType string) {
w.Header().Set("Content-Type", contentType)
index := template.Must(template.New("index").Delims("[{[", "]}]").Parse(box.MustString(file)))
data, err := getStaticData(storage)
if err != nil {
}
err := index.Execute(w, e.getStaticData())
if err != nil {
httpErr(w, r, http.StatusInternalServerError, err)
}
}
index := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
index := handle(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
if r.Method != http.MethodGet {
httpErr(w, r, http.StatusNotFound, nil)
return
return http.StatusNotFound, nil
}
w.Header().Set("x-frame-options", "SAMEORIGIN")
w.Header().Set("x-xss-protection", "1; mode=block")
handleWithData(w, r, "index.html", "text/html; charset=utf-8")
})
return handleWithStaticData(w, r, d, box, "index.html", "text/html; charset=utf-8")
}, "", storage)
static := http.StripPrefix("/static/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
e.RLockSettings()
defer e.RUnlockSettings()
static := handle(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
if r.Method != http.MethodGet {
return http.StatusNotFound, nil
}
if e.GetSettings().Branding.Files != "" {
if d.settings.Branding.Files != "" {
if strings.HasPrefix(r.URL.Path, "img/") {
path := filepath.Join(e.GetSettings().Branding.Files, r.URL.Path)
path := filepath.Join(d.settings.Branding.Files, r.URL.Path)
if _, err := os.Stat(path); err == nil {
http.ServeFile(w, r, path)
return
return 0, nil
}
} else if r.URL.Path == "custom.css" && e.GetSettings().Branding.Files != "" {
http.ServeFile(w, r, filepath.Join(e.GetSettings().Branding.Files, "custom.css"))
return
} else if r.URL.Path == "custom.css" && d.settings.Branding.Files != "" {
http.ServeFile(w, r, filepath.Join(d.settings.Branding.Files, "custom.css"))
return 0, nil
}
}
if !strings.HasSuffix(r.URL.Path, ".js") {
handler.ServeHTTP(w, r)
return
return 0, nil
}
handleWithData(w, r, r.URL.Path, "application/javascript; charset=utf-8")
}))
return handleWithStaticData(w, r, d, box, r.URL.Path, "application/javascript; charset=utf-8")
}, "/static/", storage)
return index, static
}
*/

View File

@ -5,6 +5,7 @@ import (
"net/http"
"sort"
"strconv"
"strings"
"github.com/filebrowser/filebrowser/errors"
"github.com/filebrowser/filebrowser/users"
@ -64,15 +65,15 @@ var usersGetHandler = withAdmin(func(w http.ResponseWriter, r *http.Request, d *
if err != nil {
return http.StatusInternalServerError, err
}
for _, u := range users {
u.Password = ""
}
sort.Slice(users, func(i, j int) bool {
return users[i].ID < users[j].ID
})
return renderJSON(w, r, users)
})
@ -81,7 +82,7 @@ var userGetHandler = withSelfOrAdmin(func(w http.ResponseWriter, r *http.Request
if err == errors.ErrNotExist {
return http.StatusNotFound, err
}
if err != nil {
return http.StatusInternalServerError, err
}
@ -95,85 +96,63 @@ var userDeleteHandler = withSelfOrAdmin(func(w http.ResponseWriter, r *http.Requ
if err == errors.ErrNotExist {
return http.StatusNotFound, err
}
return http.StatusOK, nil
})
/*
func (e *env) userPostHandler(w http.ResponseWriter, r *http.Request) {
_, ok := e.getAdminUser(w, r)
if !ok {
return
}
req, ok := getUser(w, r)
if !ok {
return
var userPostHandler = withAdmin(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
req, err := getUser(w, r)
if err != nil {
return http.StatusBadRequest, err
}
if len(req.Which) != 0 {
httpErr(w, r, http.StatusBadRequest, nil)
return
return http.StatusBadRequest, nil
}
if req.Data.Password == "" {
httpErr(w, r, http.StatusBadRequest, lib.ErrEmptyPassword)
return
return http.StatusBadRequest, errors.ErrEmptyPassword
}
var err error
req.Data.Password, err = lib.HashPwd(req.Data.Password)
req.Data.Password, err = users.HashPwd(req.Data.Password)
if err != nil {
httpErr(w, r, http.StatusInternalServerError, err)
return
return http.StatusInternalServerError, err
}
err = e.SaveUser(req.Data)
err = d.store.Users.Save(req.Data)
if err != nil {
httpErr(w, r, http.StatusInternalServerError, err)
return
return http.StatusInternalServerError, err
}
w.Header().Set("Location", "/settings/users/"+strconv.FormatUint(uint64(req.Data.ID), 10))
w.WriteHeader(http.StatusCreated)
}
return http.StatusCreated, nil
})
func (e *env) userPutHandler(w http.ResponseWriter, r *http.Request) {
sessionUser, modifiedID, ok := e.userSelfOrAdmin(w, r)
if !ok {
return
var userPutHandler = withSelfOrAdmin(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
req, err := getUser(w, r)
if err != nil {
return http.StatusBadRequest, err
}
req, ok := getUser(w, r)
if !ok {
return
if req.Data.ID != d.raw.(uint) {
return http.StatusBadRequest, nil
}
if req.Data.ID != modifiedID {
httpErr(w, r, http.StatusBadRequest, nil)
return
}
var err error
if len(req.Which) == 1 && req.Which[0] == "all" {
if !sessionUser.Perm.Admin {
httpErr(w, r, http.StatusForbidden, nil)
return
if !d.user.Perm.Admin {
return http.StatusForbidden, err
}
if req.Data.Password != "" {
req.Data.Password, err = lib.HashPwd(req.Data.Password)
req.Data.Password, err = users.HashPwd(req.Data.Password)
} else {
var suser *users.User
suser, err = e.GetUser(modifiedID)
suser, err = d.store.Users.Get(d.raw.(uint))
req.Data.Password = suser.Password
}
if err != nil {
httpErr(w, r, http.StatusInternalServerError, err)
return
return http.StatusInternalServerError, err
}
req.Which = []string{}
@ -181,28 +160,27 @@ func (e *env) userPutHandler(w http.ResponseWriter, r *http.Request) {
for k, v := range req.Which {
if v == "password" {
if !sessionUser.Perm.Admin && sessionUser.LockPassword {
httpErr(w, r, http.StatusForbidden, nil)
return
if !d.user.Perm.Admin && d.user.LockPassword {
return http.StatusForbidden, nil
}
req.Data.Password, err = lib.HashPwd(req.Data.Password)
req.Data.Password, err = users.HashPwd(req.Data.Password)
if err != nil {
httpErr(w, r, http.StatusInternalServerError, err)
return
return http.StatusInternalServerError, err
}
}
if !sessionUser.Perm.Admin && (v == "scope" || v == "perm" || v == "username") {
httpErr(w, r, http.StatusForbidden, nil)
return
if !d.user.Perm.Admin && (v == "scope" || v == "perm" || v == "username") {
return http.StatusForbidden, nil
}
req.Which[k] = strings.Title(v)
}
err = e.UpdateUser(req.Data, req.Which...)
err = d.store.Users.Update(req.Data, req.Which...)
if err != nil {
httpErr(w, r, http.StatusInternalServerError, err)
return http.StatusInternalServerError, err
}
} */
return http.StatusOK, nil
})

33
storage/bolt/auth.go Normal file
View File

@ -0,0 +1,33 @@
package bolt
import (
"github.com/asdine/storm"
"github.com/filebrowser/filebrowser/auth"
"github.com/filebrowser/filebrowser/errors"
"github.com/filebrowser/filebrowser/settings"
)
type authBackend struct {
db *storm.DB
}
func (s authBackend) Get(t settings.AuthMethod) (auth.Auther, error) {
var auther auth.Auther
switch t {
case auth.MethodJSONAuth:
auther = &auth.JSONAuth{}
case auth.MethodProxyAuth:
auther = &auth.ProxyAuth{}
case auth.MethodNoAuth:
auther = &auth.NoAuth{}
default:
return nil, errors.ErrInvalidAuthMethod
}
return auther, get(s.db, "auther", auther)
}
func (s authBackend) Save(a auth.Auther) error {
return save(s.db, "auther", a)
}

View File

@ -1,9 +1,25 @@
package bolt
import "github.com/asdine/storm"
import (
"github.com/filebrowser/filebrowser/settings"
"github.com/asdine/storm"
"github.com/filebrowser/filebrowser/auth"
"github.com/filebrowser/filebrowser/share"
"github.com/filebrowser/filebrowser/storage"
"github.com/filebrowser/filebrowser/users"
)
// Backend implements storage.Backend
// using Bolt DB.
type Backend struct {
DB *storm.DB
// NewStorage creates a storage.Storage based on Bolt DB.
func NewStorage(db *storm.DB) *storage.Storage {
users := users.NewStorage(usersBackend{db: db})
share := share.NewStorage(shareBackend{db: db})
settings := settings.NewStorage(settingsBackend{ db: db})
auth := auth.NewStorage(authBackend{db: db}, users)
return &storage.Storage{
Auth: auth,
Users: users,
Share: share,
Settings: settings,
}
}

View File

@ -2,49 +2,18 @@ package bolt
import (
"github.com/asdine/storm"
"github.com/filebrowser/filebrowser/auth"
"github.com/filebrowser/filebrowser/settings"
)
func (b Backend) get(name string, to interface{}) error {
err := b.DB.Get("config", name, to)
if err == storm.ErrNotFound {
return lib.ErrNotExist
}
return err
type settingsBackend struct {
db *storm.DB
}
func (b Backend) save(name string, from interface{}) error {
return b.DB.Set("config", name, from)
}
func (b Backend) GetSettings() (*settings.Settings, error) {
func (s settingsBackend) Get() (*settings.Settings, error) {
settings := &settings.Settings{}
return settings, b.get("settings", settings)
return settings, get(s.db, "settings", settings)
}
func (b Backend) SaveSettings(s *settings.Settings) error {
return b.save("settings", s)
}
func (b Backend) GetAuther(t lib.AuthMethod) (lib.Auther, error) {
var auther lib.Auther
switch t {
case auth.MethodJSONAuth:
auther = &auth.JSONAuth{}
case auth.MethodProxyAuth:
auther = &auth.ProxyAuth{}
case auth.MethodNoAuth:
auther = &auth.NoAuth{}
default:
return nil, lib.ErrInvalidAuthMethod
}
return auther, b.get("auther", auther)
}
func (b Backend) SaveAuther(a lib.Auther) error {
return b.save("auther", a)
func (s settingsBackend) Save(settings *settings.Settings) error {
return save(s.db, "settings", settings)
}

View File

@ -3,43 +3,48 @@ package bolt
import (
"github.com/asdine/storm"
"github.com/asdine/storm/q"
"github.com/filebrowser/filebrowser/errors"
"github.com/filebrowser/filebrowser/share"
)
func (s Backend) GetLinkByHash(hash string) (*lib.ShareLink, error) {
var v lib.ShareLink
err := s.DB.One("Hash", hash, &v)
type shareBackend struct {
db *storm.DB
}
func (s shareBackend) GetByHash(hash string) (*share.Link, error) {
var v share.Link
err := s.db.One("Hash", hash, &v)
if err == storm.ErrNotFound {
return nil, lib.ErrNotExist
return nil, errors.ErrNotExist
}
return &v, err
}
func (s Backend) GetLinkPermanent(path string) (*lib.ShareLink, error) {
var v lib.ShareLink
err := s.DB.Select(q.Eq("Path", path), q.Eq("Expires", false)).First(&v)
func (s shareBackend) GetPermanent(path string) (*share.Link, error) {
var v share.Link
err := s.db.Select(q.Eq("Path", path), q.Eq("Expires", false)).First(&v)
if err == storm.ErrNotFound {
return nil, lib.ErrNotExist
return nil, errors.ErrNotExist
}
return &v, err
}
func (s Backend) GetLinksByPath(hash string) ([]*lib.ShareLink, error) {
var v []*lib.ShareLink
err := s.DB.Find("Path", hash, &v)
func (s shareBackend) Gets(hash string) ([]*share.Link, error) {
var v []*share.Link
err := s.db.Find("Path", hash, &v)
if err == storm.ErrNotFound {
return v, lib.ErrNotExist
return v, errors.ErrNotExist
}
return v, err
}
func (s Backend) SaveLink(l *lib.ShareLink) error {
return s.DB.Save(l)
func (s shareBackend) Save(l *share.Link) error {
return s.db.Save(l)
}
func (s Backend) DeleteLink(hash string) error {
return s.DB.DeleteStruct(&lib.ShareLink{Hash: hash})
func (s shareBackend) Delete(hash string) error {
return s.db.DeleteStruct(&share.Link{Hash: hash})
}

View File

@ -4,14 +4,19 @@ import (
"reflect"
"github.com/asdine/storm"
"github.com/filebrowser/filebrowser/errors"
"github.com/filebrowser/filebrowser/users"
)
func (st Backend) GetUserByID(id uint) (*lib.User, error) {
user := &lib.User{}
err := st.DB.One("ID", id, user)
type usersBackend struct {
db *storm.DB
}
func (st usersBackend) GetByID(id uint) (*users.User, error) {
user := &users.User{}
err := st.db.One("ID", id, user)
if err == storm.ErrNotFound {
return nil, lib.ErrNotExist
return nil, errors.ErrNotExist
}
if err != nil {
@ -21,11 +26,11 @@ func (st Backend) GetUserByID(id uint) (*lib.User, error) {
return user, nil
}
func (st Backend) GetUserByUsername(username string) (*lib.User, error) {
user := &lib.User{}
err := st.DB.One("Username", username, user)
func (st usersBackend) GetByUsername(username string) (*users.User, error) {
user := &users.User{}
err := st.db.One("Username", username, user)
if err == storm.ErrNotFound {
return nil, lib.ErrNotExist
return nil, errors.ErrNotExist
}
if err != nil {
@ -35,11 +40,11 @@ func (st Backend) GetUserByUsername(username string) (*lib.User, error) {
return user, nil
}
func (st Backend) GetUsers() ([]*lib.User, error) {
users := []*lib.User{}
err := st.DB.All(&users)
func (st usersBackend) Gets() ([]*users.User, error) {
users := []*users.User{}
err := st.db.All(&users)
if err == storm.ErrNotFound {
return nil, lib.ErrNotExist
return nil, errors.ErrNotExist
}
if err != nil {
@ -49,14 +54,14 @@ func (st Backend) GetUsers() ([]*lib.User, error) {
return users, err
}
func (st Backend) UpdateUser(user *lib.User, fields ...string) error {
func (st usersBackend) Update(user *users.User, fields ...string) error {
if len(fields) == 0 {
return st.SaveUser(user)
return st.Save(user)
}
for _, field := range fields {
val := reflect.ValueOf(user).Elem().FieldByName(field).Interface()
if err := st.DB.UpdateField(user, field, val); err != nil {
if err := st.db.UpdateField(user, field, val); err != nil {
return err
}
}
@ -64,23 +69,23 @@ func (st Backend) UpdateUser(user *lib.User, fields ...string) error {
return nil
}
func (st Backend) SaveUser(user *lib.User) error {
err := st.DB.Save(user)
func (st usersBackend) Save(user *users.User) error {
err := st.db.Save(user)
if err == storm.ErrAlreadyExists {
return lib.ErrExist
return errors.ErrExist
}
return err
}
func (st Backend) DeleteUserByID(id uint) error {
return st.DB.DeleteStruct(&lib.User{ID: id})
func (st usersBackend) DeleteByID(id uint) error {
return st.db.DeleteStruct(&users.User{ID: id})
}
func (st Backend) DeleteUserByUsername(username string) error {
user, err := st.GetUserByUsername(username)
func (st usersBackend) DeleteByUsername(username string) error {
user, err := st.GetByUsername(username)
if err != nil {
return err
}
return st.DB.DeleteStruct(user)
return st.db.DeleteStruct(user)
}

19
storage/bolt/utils.go Normal file
View File

@ -0,0 +1,19 @@
package bolt
import (
"github.com/asdine/storm"
"github.com/filebrowser/filebrowser/errors"
)
func get(db *storm.DB, name string, to interface{}) error {
err := db.Get("config", name, to)
if err == storm.ErrNotFound {
return errors.ErrNotExist
}
return err
}
func save(db *storm.DB, name string, from interface{}) error {
return db.Set("config", name, from)
}

View File

@ -1,10 +0,0 @@
package storage
import "crypto/rand"
func generateRandomBytes(n int) ([]byte, error) {
b := make([]byte, n)
_, err := rand.Read(b)
// Note that err == nil only if we read len(b) bytes.
return b, err
}