From 2156b3e68b9db10f996628708aaf92dba54cc43f Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Sun, 6 Jan 2019 08:58:31 +0000 Subject: [PATCH] feat: add global scope License: MIT Signed-off-by: Henrique Dias --- auth/auth.go | 5 +- auth/json.go | 10 +--- auth/none.go | 10 +--- auth/proxy.go | 9 +--- auth/storage.go | 10 +--- cmd/config.go | 4 +- cmd/config_init.go | 11 ++++- cmd/config_set.go | 2 +- cmd/root.go | 17 +++++-- cmd/rules.go | 2 +- cmd/users.go | 88 +++++++++++++++++----------------- cmd/users_find.go | 10 ++-- cmd/users_new.go | 4 +- cmd/users_update.go | 12 +++-- http/auth.go | 4 +- http/public.go | 2 +- http/users.go | 6 +-- settings/settings.go | 1 + storage/bolt/importer/users.go | 7 ++- users/storage.go | 12 ++--- users/users.go | 17 ++++--- 21 files changed, 122 insertions(+), 121 deletions(-) diff --git a/auth/auth.go b/auth/auth.go index bcde03d7..86b56a04 100644 --- a/auth/auth.go +++ b/auth/auth.go @@ -3,13 +3,12 @@ package auth import ( "net/http" + "github.com/filebrowser/filebrowser/v2/settings" "github.com/filebrowser/filebrowser/v2/users" ) // Auther is the authentication interface. type Auther interface { // Auth is called to authenticate a request. - Auth(*http.Request) (*users.User, error) - // SetStorage attaches the Storage instance. - SetStorage(*users.Storage) + Auth(*http.Request, *users.Storage, *settings.Settings) (*users.User, error) } diff --git a/auth/json.go b/auth/json.go index ecf067a2..9bd86fe8 100644 --- a/auth/json.go +++ b/auth/json.go @@ -23,11 +23,10 @@ type jsonCred struct { // JSONAuth is a json implementaion of an Auther. type JSONAuth struct { ReCaptcha *ReCaptcha - storage *users.Storage } // Auth authenticates the user via a json in content body. -func (a *JSONAuth) Auth(r *http.Request) (*users.User, error) { +func (a *JSONAuth) Auth(r *http.Request, sto *users.Storage, set *settings.Settings) (*users.User, error) { var cred jsonCred if r.Body == nil { @@ -52,7 +51,7 @@ func (a *JSONAuth) Auth(r *http.Request) (*users.User, error) { } } - u, err := a.storage.Get(cred.Username) + u, err := sto.Get(set.Scope, cred.Username) if err != nil || !users.CheckPwd(cred.Password, u.Password) { return nil, os.ErrPermission } @@ -60,11 +59,6 @@ func (a *JSONAuth) Auth(r *http.Request) (*users.User, error) { return u, nil } -// SetStorage attaches the storage to the auther. -func (a *JSONAuth) SetStorage(s *users.Storage) { - a.storage = s -} - const reCaptchaAPI = "/recaptcha/api/siteverify" // ReCaptcha identifies a recaptcha conenction. diff --git a/auth/none.go b/auth/none.go index 0d3e2293..76312881 100644 --- a/auth/none.go +++ b/auth/none.go @@ -12,15 +12,9 @@ const MethodNoAuth settings.AuthMethod = "noauth" // NoAuth is no auth implementation of auther. type NoAuth struct { - storage *users.Storage } // Auth uses authenticates user 1. -func (a *NoAuth) Auth(r *http.Request) (*users.User, error) { - return a.storage.Get(1) -} - -// SetStorage attaches the storage to the auther. -func (a *NoAuth) SetStorage(s *users.Storage) { - a.storage = s +func (a *NoAuth) Auth(r *http.Request, sto *users.Storage, set *settings.Settings) (*users.User, error) { + return sto.Get(set.Scope, 1) } diff --git a/auth/proxy.go b/auth/proxy.go index f23b70fb..82c415bf 100644 --- a/auth/proxy.go +++ b/auth/proxy.go @@ -19,17 +19,12 @@ type ProxyAuth struct { } // Auth authenticates the user via an HTTP header. -func (a *ProxyAuth) Auth(r *http.Request) (*users.User, error) { +func (a *ProxyAuth) Auth(r *http.Request, sto *users.Storage, set *settings.Settings) (*users.User, error) { username := r.Header.Get(a.Header) - user, err := a.storage.Get(username) + user, err := sto.Get(set.Scope, username) if err == errors.ErrNotExist { return nil, os.ErrPermission } return user, err } - -// SetStorage attaches the storage to the auther. -func (a *ProxyAuth) SetStorage(s *users.Storage) { - a.storage = s -} diff --git a/auth/storage.go b/auth/storage.go index b5bd5e83..2cf63e05 100644 --- a/auth/storage.go +++ b/auth/storage.go @@ -22,15 +22,9 @@ func NewStorage(back StorageBackend, users *users.Storage) *Storage { return &Storage{back: back, users: users} } -// Get wraps a StorageBackend.Get and calls SetStorage on the auther. +// Get wraps a StorageBackend.Get. func (s *Storage) Get(t settings.AuthMethod) (Auther, error) { - auther, err := s.back.Get(t) - if err != nil { - return nil, err - } - - auther.SetStorage(s.users) - return auther, nil + return s.back.Get(t) } // Save wraps a StorageBackend.Save. diff --git a/cmd/config.go b/cmd/config.go index e03fb354..9a2ae3f8 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -30,10 +30,11 @@ var configCmd = &cobra.Command{ } func addConfigFlags(cmd *cobra.Command) { - addUserFlags(cmd) + addUserFlags(cmd, "defaults.") cmd.Flags().StringP("baseURL", "b", "/", "base url of this installation") cmd.Flags().BoolP("signup", "s", false, "allow users to signup") cmd.Flags().String("shell", "", "shell command to which other commands should be appended") + cmd.Flags().String("scope", "", "scope to prepend to a user's scope when it is relative (default is current working directory)") cmd.Flags().StringP("address", "a", "127.0.0.1", "default address to listen to") cmd.Flags().StringP("log", "l", "stderr", "log output") @@ -102,6 +103,7 @@ func printSettings(s *settings.Settings, auther auth.Auther) { fmt.Fprintf(w, "Auth method:\t%s\n", s.AuthMethod) fmt.Fprintf(w, "Shell:\t%s\t\n", strings.Join(s.Shell, " ")) fmt.Fprintf(w, "Log:\t%s\t\n", s.Log) + fmt.Fprintf(w, "Scope:\t%s\t\n", s.Scope) fmt.Fprintln(w, "\nServer:") fmt.Fprintf(w, "\tAddress:\t%s\n", s.Server.Address) fmt.Fprintf(w, "\tPort:\t%d\n", s.Server.Port) diff --git a/cmd/config_init.go b/cmd/config_init.go index cec455a0..e53b74af 100644 --- a/cmd/config_init.go +++ b/cmd/config_init.go @@ -15,7 +15,6 @@ func init() { configCmd.AddCommand(configInitCmd) rootCmd.AddCommand(configInitCmd) addConfigFlags(configInitCmd) - configInitCmd.MarkFlagRequired("scope") } var configInitCmd = &cobra.Command{ @@ -33,9 +32,16 @@ override the options.`, } defaults := settings.UserDefaults{} - getUserDefaults(cmd, &defaults, true) + getUserDefaults(cmd, &defaults, "defaults.", true) authMethod, auther := getAuthentication(cmd) + var err error + scope := mustGetString(cmd, "scope") + if scope == "" { + scope, err = os.Getwd() + checkErr(err) + } + db, err := storm.Open(databasePath) checkErr(err) defer db.Close() @@ -45,6 +51,7 @@ override the options.`, BaseURL: mustGetString(cmd, "baseURL"), Log: mustGetString(cmd, "log"), Signup: mustGetBool(cmd, "signup"), + Scope: scope, Shell: strings.Split(strings.TrimSpace(mustGetString(cmd, "shell")), " "), AuthMethod: authMethod, Defaults: defaults, diff --git a/cmd/config_set.go b/cmd/config_set.go index b2d4658a..8b8e3a2d 100644 --- a/cmd/config_set.go +++ b/cmd/config_set.go @@ -57,7 +57,7 @@ you want to change.`, } }) - getUserDefaults(cmd, &s.Defaults, false) + getUserDefaults(cmd, &s.Defaults, "defaults.", false) var auther auth.Auther if hasAuth { diff --git a/cmd/root.go b/cmd/root.go index 9444dc4c..8eb551d5 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -3,7 +3,6 @@ package cmd import ( "crypto/rand" "crypto/tls" - "errors" "io/ioutil" "log" "net" @@ -35,7 +34,7 @@ func init() { rootCmd.Flags().IntP("port", "p", 0, "port to listen on (default comes from database)") rootCmd.Flags().StringP("cert", "c", "", "tls certificate (default comes from database)") rootCmd.Flags().StringP("key", "k", "", "tls key (default comes from database)") - rootCmd.Flags().StringP("scope", "s", "", "scope for users") + rootCmd.Flags().StringP("scope", "s", "", "scope to prepend to a user's scope when it is relative (default comes from database)") } var rootCmd = &cobra.Command{ @@ -103,9 +102,11 @@ func serverVisitAndReplace(cmd *cobra.Command, s *settings.Settings) { } func quickSetup(cmd *cobra.Command) { + var err error scope := mustGetString(cmd, "scope") if scope == "" { - panic(errors.New("scope flag must be set for quick setup")) + scope, err = os.Getwd() + checkErr(err) } db, err := storm.Open(databasePath) @@ -115,6 +116,7 @@ func quickSetup(cmd *cobra.Command) { set := &settings.Settings{ Key: generateRandomBytes(64), // 256 bit BaseURL: "", + Scope: scope, Log: "stderr", Signup: false, AuthMethod: auth.MethodJSONAuth, @@ -125,7 +127,7 @@ func quickSetup(cmd *cobra.Command) { TLSKey: mustGetString(cmd, "key"), }, Defaults: settings.UserDefaults{ - Scope: scope, + Scope: ".", Locale: "en", Perm: users.Permissions{ Admin: false, @@ -169,6 +171,13 @@ func startServer(cmd *cobra.Command, st *storage.Storage) { settings, err := st.Settings.Get() checkErr(err) + scope := mustGetString(cmd, "scope") + if scope != "" { + settings.Scope = scope + err = st.Settings.Save(settings) + checkErr(err) + } + serverVisitAndReplace(cmd, settings) setupLogger(settings) diff --git a/cmd/rules.go b/cmd/rules.go index 99f20814..2a7d219d 100644 --- a/cmd/rules.go +++ b/cmd/rules.go @@ -39,7 +39,7 @@ func runRules(cmd *cobra.Command, users func(*users.User, *storage.Storage), glo id := getUserIdentifier(cmd) if id != nil { - user, err := st.Users.Get(id) + user, err := st.Users.Get("", id) checkErr(err) if users != nil { diff --git a/cmd/users.go b/cmd/users.go index e497e82b..215a142b 100644 --- a/cmd/users.go +++ b/cmd/users.go @@ -64,22 +64,22 @@ func usernameOrIDRequired(cmd *cobra.Command, args []string) error { return nil } -func addUserFlags(cmd *cobra.Command) { - cmd.Flags().Bool("perm.admin", false, "admin perm for users") - cmd.Flags().Bool("perm.execute", true, "execute perm for users") - cmd.Flags().Bool("perm.create", true, "create perm for users") - cmd.Flags().Bool("perm.rename", true, "rename perm for users") - cmd.Flags().Bool("perm.modify", true, "modify perm for users") - cmd.Flags().Bool("perm.delete", true, "delete perm for users") - cmd.Flags().Bool("perm.share", true, "share perm for users") - cmd.Flags().Bool("perm.download", true, "download perm for users") - cmd.Flags().String("sorting.by", "name", "sorting mode (name, size or modified)") - cmd.Flags().Bool("sorting.asc", false, "sorting by ascending order") - cmd.Flags().Bool("lockPassword", false, "lock password") - 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(users.ListViewMode), "view mode for users") +func addUserFlags(cmd *cobra.Command, prepend string) { + cmd.Flags().Bool(prepend+"perm.admin", false, "admin perm for users") + cmd.Flags().Bool(prepend+"perm.execute", true, "execute perm for users") + cmd.Flags().Bool(prepend+"perm.create", true, "create perm for users") + cmd.Flags().Bool(prepend+"perm.rename", true, "rename perm for users") + cmd.Flags().Bool(prepend+"perm.modify", true, "modify perm for users") + cmd.Flags().Bool(prepend+"perm.delete", true, "delete perm for users") + cmd.Flags().Bool(prepend+"perm.share", true, "share perm for users") + cmd.Flags().Bool(prepend+"perm.download", true, "download perm for users") + cmd.Flags().String(prepend+"sorting.by", "name", "sorting mode (name, size or modified)") + cmd.Flags().Bool(prepend+"sorting.asc", false, "sorting by ascending order") + cmd.Flags().Bool(prepend+"lockPassword", false, "lock password") + cmd.Flags().StringSlice(prepend+"commands", nil, "a list of the commands a user can execute") + cmd.Flags().String(prepend+"scope", "", "scope for users") + cmd.Flags().String(prepend+"locale", "en", "locale for users") + cmd.Flags().String(prepend+"viewMode", string(users.ListViewMode), "view mode for users") } func getViewMode(cmd *cobra.Command) users.ViewMode { @@ -90,39 +90,39 @@ func getViewMode(cmd *cobra.Command) users.ViewMode { return viewMode } -func getUserDefaults(cmd *cobra.Command, defaults *settings.UserDefaults, all bool) { +func getUserDefaults(cmd *cobra.Command, defaults *settings.UserDefaults, prepend string, all bool) { visit := func(flag *pflag.Flag) { switch flag.Name { - case "scope": - defaults.Scope = mustGetString(cmd, "scope") - case "locale": - defaults.Locale = mustGetString(cmd, "locale") - case "viewMode": + case prepend+"scope": + defaults.Scope = mustGetString(cmd, flag.Name) + case prepend+"locale": + defaults.Locale = mustGetString(cmd, flag.Name) + case prepend+"viewMode": defaults.ViewMode = getViewMode(cmd) - case "perm.admin": - defaults.Perm.Admin = mustGetBool(cmd, "perm.admin") - case "perm.execute": - defaults.Perm.Execute = mustGetBool(cmd, "perm.execute") - case "perm.create": - defaults.Perm.Create = mustGetBool(cmd, "perm.create") - case "perm.rename": - defaults.Perm.Rename = mustGetBool(cmd, "perm.rename") - case "perm.modify": - defaults.Perm.Modify = mustGetBool(cmd, "perm.modify") - case "perm.delete": - defaults.Perm.Delete = mustGetBool(cmd, "perm.delete") - case "perm.share": - defaults.Perm.Share = mustGetBool(cmd, "perm.share") - case "perm.download": - defaults.Perm.Download = mustGetBool(cmd, "perm.download") - case "commands": - commands, err := cmd.Flags().GetStringSlice("commands") + case prepend+"perm.admin": + defaults.Perm.Admin = mustGetBool(cmd, flag.Name) + case prepend+"perm.execute": + defaults.Perm.Execute = mustGetBool(cmd, flag.Name) + case prepend+"perm.create": + defaults.Perm.Create = mustGetBool(cmd, flag.Name) + case prepend+"perm.rename": + defaults.Perm.Rename = mustGetBool(cmd, flag.Name) + case prepend+"perm.modify": + defaults.Perm.Modify = mustGetBool(cmd, flag.Name) + case prepend+"perm.delete": + defaults.Perm.Delete = mustGetBool(cmd, flag.Name) + case prepend+"perm.share": + defaults.Perm.Share = mustGetBool(cmd, flag.Name) + case prepend+"perm.download": + defaults.Perm.Download = mustGetBool(cmd, flag.Name) + case prepend+"commands": + commands, err := cmd.Flags().GetStringSlice(flag.Name) checkErr(err) defaults.Commands = commands - case "sorting.by": - defaults.Sorting.By = mustGetString(cmd, "sorting.by") - case "sorting.asc": - defaults.Sorting.Asc = mustGetBool(cmd, "sorting.asc") + case prepend+"sorting.by": + defaults.Sorting.By = mustGetString(cmd, flag.Name) + case prepend+"sorting.asc": + defaults.Sorting.Asc = mustGetBool(cmd, flag.Name) } } diff --git a/cmd/users_find.go b/cmd/users_find.go index 9fdd92b6..126c7354 100644 --- a/cmd/users_find.go +++ b/cmd/users_find.go @@ -32,19 +32,21 @@ var findUsers = func(cmd *cobra.Command, args []string) { defer db.Close() st := getStorage(db) + settings, err := st.Settings.Get() + checkErr(err) + username, _ := cmd.Flags().GetString("username") id, _ := cmd.Flags().GetUint("id") - var err error var list []*users.User var user *users.User if username != "" { - user, err = st.Users.Get(username) + user, err = st.Users.Get(settings.Scope, username) } else if id != 0 { - user, err = st.Users.Get(id) + user, err = st.Users.Get(settings.Scope, id) } else { - list, err = st.Users.Gets() + list, err = st.Users.Gets(settings.Scope) } checkErr(err) diff --git a/cmd/users_new.go b/cmd/users_new.go index 47480d65..f181a61f 100644 --- a/cmd/users_new.go +++ b/cmd/users_new.go @@ -8,7 +8,7 @@ import ( func init() { usersCmd.AddCommand(usersNewCmd) - addUserFlags(usersNewCmd) + addUserFlags(usersNewCmd, "") usersNewCmd.Flags().StringP("username", "u", "", "new users's username") usersNewCmd.Flags().StringP("password", "p", "", "new user's password") usersNewCmd.MarkFlagRequired("username") @@ -27,7 +27,7 @@ var usersNewCmd = &cobra.Command{ s, err := st.Settings.Get() checkErr(err) - getUserDefaults(cmd, &s.Defaults, false) + getUserDefaults(cmd, &s.Defaults, "", false) password, _ := cmd.Flags().GetString("password") password, err = users.HashPwd(password) diff --git a/cmd/users_update.go b/cmd/users_update.go index ebeef419..fd22fc91 100644 --- a/cmd/users_update.go +++ b/cmd/users_update.go @@ -12,7 +12,7 @@ func init() { usersUpdateCmd.Flags().UintP("id", "i", 0, "id of the user") usersUpdateCmd.Flags().StringP("username", "u", "", "user to change or new username if flag 'id' is set") usersUpdateCmd.Flags().StringP("password", "p", "", "new password") - addUserFlags(usersUpdateCmd) + addUserFlags(usersUpdateCmd, "") } var usersUpdateCmd = &cobra.Command{ @@ -26,17 +26,19 @@ options you want to change.`, defer db.Close() st := getStorage(db) + set, err := st.Settings.Get() + checkErr(err) + id, _ := cmd.Flags().GetUint("id") username := mustGetString(cmd, "username") password := mustGetString(cmd, "password") var user *users.User - var err error if id != 0 { - user, err = st.Users.Get(id) + user, err = st.Users.Get(set.Scope, id) } else { - user, err = st.Users.Get(username) + user, err = st.Users.Get(set.Scope, username) } checkErr(err) @@ -49,7 +51,7 @@ options you want to change.`, Sorting: user.Sorting, Commands: user.Commands, } - getUserDefaults(cmd, &defaults, false) + getUserDefaults(cmd, &defaults, "", false) user.Scope = defaults.Scope user.Locale = defaults.Locale user.ViewMode = defaults.ViewMode diff --git a/http/auth.go b/http/auth.go index 9ea0a889..2e01ddf0 100644 --- a/http/auth.go +++ b/http/auth.go @@ -67,7 +67,7 @@ func withUser(fn handleFunc) handleFunc { w.Header().Add("X-Renew-Token", "true") } - d.user, err = d.store.Users.Get(tk.User.ID) + d.user, err = d.store.Users.Get(d.settings.Scope, tk.User.ID) if err != nil { return http.StatusInternalServerError, err } @@ -91,7 +91,7 @@ var loginHandler = func(w http.ResponseWriter, r *http.Request, d *data) (int, e return http.StatusInternalServerError, err } - user, err := auther.Auth(r) + user, err := auther.Auth(r, d.store.Users, d.Settings) if err == os.ErrPermission { return http.StatusForbidden, nil } else if err != nil { diff --git a/http/public.go b/http/public.go index 656e3698..afab24a6 100644 --- a/http/public.go +++ b/http/public.go @@ -13,7 +13,7 @@ var withHashFile = func(fn handleFunc) handleFunc { return errToStatus(err), err } - user, err := d.store.Users.Get(link.UserID) + user, err := d.store.Users.Get(d.settings.Scope, link.UserID) if err != nil { return errToStatus(err), err } diff --git a/http/users.go b/http/users.go index 545b2536..ad547435 100644 --- a/http/users.go +++ b/http/users.go @@ -61,7 +61,7 @@ func withSelfOrAdmin(fn handleFunc) handleFunc { } var usersGetHandler = withAdmin(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { - users, err := d.store.Users.Gets() + users, err := d.store.Users.Gets(d.settings.Scope) if err != nil { return http.StatusInternalServerError, err } @@ -78,7 +78,7 @@ var usersGetHandler = withAdmin(func(w http.ResponseWriter, r *http.Request, d * }) var userGetHandler = withSelfOrAdmin(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { - u, err := d.store.Users.Get(d.raw.(uint)) + u, err := d.store.Users.Get(d.settings.Scope, d.raw.(uint)) if err == errors.ErrNotExist { return http.StatusNotFound, err } @@ -147,7 +147,7 @@ var userPutHandler = withSelfOrAdmin(func(w http.ResponseWriter, r *http.Request req.Data.Password, err = users.HashPwd(req.Data.Password) } else { var suser *users.User - suser, err = d.store.Users.Get(d.raw.(uint)) + suser, err = d.store.Users.Get(d.settings.Scope, d.raw.(uint)) req.Data.Password = suser.Password } diff --git a/settings/settings.go b/settings/settings.go index 60285721..e958514e 100644 --- a/settings/settings.go +++ b/settings/settings.go @@ -10,6 +10,7 @@ type Settings struct { Key []byte `json:"key"` BaseURL string `json:"baseURL"` Log string `json:"log"` + Scope string `json:"scope"` Server Server `json:"server"` Signup bool `json:"signup"` Defaults UserDefaults `json:"defaults"` diff --git a/storage/bolt/importer/users.go b/storage/bolt/importer/users.go index 660403b4..5d5c7e83 100644 --- a/storage/bolt/importer/users.go +++ b/storage/bolt/importer/users.go @@ -3,7 +3,7 @@ package importer import ( "encoding/json" "fmt" - "path/filepath" + "os" "github.com/asdine/storm" "github.com/filebrowser/filebrowser/v2/rules" @@ -52,7 +52,6 @@ func readOldUsers(db *storm.DB) ([]*oldUser, error) { } func convertUsersToNew(old []*oldUser) ([]*users.User, error) { - var err error list := []*users.User{} for _, oldUser := range old { @@ -82,12 +81,12 @@ func convertUsersToNew(old []*oldUser) ([]*users.User, error) { user.Rules = append(user.Rules, *rule) } - user.Scope, err = filepath.Abs(user.Scope) + baseScope, err := os.Getwd() if err != nil { return nil, err } - err = user.Clean() + err = user.Clean(baseScope) if err != nil { return nil, err } diff --git a/users/storage.go b/users/storage.go index 1366b968..ce3e7514 100644 --- a/users/storage.go +++ b/users/storage.go @@ -36,7 +36,7 @@ func NewStorage(back StorageBackend) *Storage { // Get allows you to get a user by its name or username. The provided // id must be a string for username lookup or a uint for id lookup. If id // is neither, a ErrInvalidDataType will be returned. -func (s *Storage) Get(id interface{}) (*User, error) { +func (s *Storage) Get(baseScope string, id interface{}) (*User, error) { var ( user *User err error @@ -55,19 +55,19 @@ func (s *Storage) Get(id interface{}) (*User, error) { return nil, err } - user.Clean() + user.Clean(baseScope) return user, err } // Gets gets a list of all users. -func (s *Storage) Gets() ([]*User, error) { +func (s *Storage) Gets(baseScope string) ([]*User, error) { users, err := s.back.Gets() if err != nil { return nil, err } for _, user := range users { - user.Clean() + user.Clean(baseScope) } return users, err @@ -75,7 +75,7 @@ func (s *Storage) Gets() ([]*User, error) { // Update updates a user in the database. func (s *Storage) Update(user *User, fields ...string) error { - err := user.Clean(fields...) + err := user.Clean("", fields...) if err != nil { return err } @@ -93,7 +93,7 @@ func (s *Storage) Update(user *User, fields ...string) error { // Save saves the user in a storage. func (s *Storage) Save(user *User) error { - if err := user.Clean(); err != nil { + if err := user.Clean(""); err != nil { return err } diff --git a/users/users.go b/users/users.go index 8d530048..387a4eaa 100644 --- a/users/users.go +++ b/users/users.go @@ -1,10 +1,11 @@ package users import ( - "github.com/filebrowser/filebrowser/v2/errors" "path/filepath" "regexp" + "github.com/filebrowser/filebrowser/v2/errors" + "github.com/filebrowser/filebrowser/v2/files" "github.com/filebrowser/filebrowser/v2/rules" "github.com/spf13/afero" @@ -51,7 +52,7 @@ var checkableFields = []string{ // Clean cleans up a user and verifies if all its fields // are alright to be saved. -func (u *User) Clean(fields ...string) error { +func (u *User) Clean(baseScope string, fields ...string) error { if len(fields) == 0 { fields = checkableFields } @@ -66,10 +67,6 @@ func (u *User) Clean(fields ...string) error { if u.Password == "" { return errors.ErrEmptyPassword } - case "Scope": - if !filepath.IsAbs(u.Scope) { - return errors.ErrScopeIsRelative - } case "ViewMode": if u.ViewMode == "" { u.ViewMode = ListViewMode @@ -90,7 +87,13 @@ func (u *User) Clean(fields ...string) error { } if u.Fs == nil { - u.Fs = afero.NewBasePathFs(afero.NewOsFs(), u.Scope) + scope := u.Scope + + if !filepath.IsAbs(scope) { + scope = filepath.Join(baseScope, scope) + } + + u.Fs = afero.NewBasePathFs(afero.NewOsFs(), scope) } return nil