feat: add global scope

License: MIT
Signed-off-by: Henrique Dias <hacdias@gmail.com>
This commit is contained in:
Henrique Dias 2019-01-06 08:58:31 +00:00
parent c830b80269
commit 2156b3e68b
21 changed files with 122 additions and 121 deletions

View File

@ -3,13 +3,12 @@ package auth
import ( import (
"net/http" "net/http"
"github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/users" "github.com/filebrowser/filebrowser/v2/users"
) )
// Auther is the authentication interface. // Auther is the authentication interface.
type Auther interface { type Auther interface {
// Auth is called to authenticate a request. // Auth is called to authenticate a request.
Auth(*http.Request) (*users.User, error) Auth(*http.Request, *users.Storage, *settings.Settings) (*users.User, error)
// SetStorage attaches the Storage instance.
SetStorage(*users.Storage)
} }

View File

@ -23,11 +23,10 @@ type jsonCred struct {
// JSONAuth is a json implementaion of an Auther. // JSONAuth is a json implementaion of an Auther.
type JSONAuth struct { type JSONAuth struct {
ReCaptcha *ReCaptcha ReCaptcha *ReCaptcha
storage *users.Storage
} }
// Auth authenticates the user via a json in content body. // 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 var cred jsonCred
if r.Body == nil { 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) { if err != nil || !users.CheckPwd(cred.Password, u.Password) {
return nil, os.ErrPermission return nil, os.ErrPermission
} }
@ -60,11 +59,6 @@ func (a *JSONAuth) Auth(r *http.Request) (*users.User, error) {
return u, nil 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" const reCaptchaAPI = "/recaptcha/api/siteverify"
// ReCaptcha identifies a recaptcha conenction. // ReCaptcha identifies a recaptcha conenction.

View File

@ -12,15 +12,9 @@ const MethodNoAuth settings.AuthMethod = "noauth"
// NoAuth is no auth implementation of auther. // NoAuth is no auth implementation of auther.
type NoAuth struct { type NoAuth struct {
storage *users.Storage
} }
// Auth uses authenticates user 1. // Auth uses authenticates user 1.
func (a *NoAuth) Auth(r *http.Request) (*users.User, error) { func (a *NoAuth) Auth(r *http.Request, sto *users.Storage, set *settings.Settings) (*users.User, error) {
return a.storage.Get(1) return sto.Get(set.Scope, 1)
}
// SetStorage attaches the storage to the auther.
func (a *NoAuth) SetStorage(s *users.Storage) {
a.storage = s
} }

View File

@ -19,17 +19,12 @@ type ProxyAuth struct {
} }
// Auth authenticates the user via an HTTP header. // 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) username := r.Header.Get(a.Header)
user, err := a.storage.Get(username) user, err := sto.Get(set.Scope, username)
if err == errors.ErrNotExist { if err == errors.ErrNotExist {
return nil, os.ErrPermission return nil, os.ErrPermission
} }
return user, err return user, err
} }
// SetStorage attaches the storage to the auther.
func (a *ProxyAuth) SetStorage(s *users.Storage) {
a.storage = s
}

View File

@ -22,15 +22,9 @@ func NewStorage(back StorageBackend, users *users.Storage) *Storage {
return &Storage{back: back, users: users} 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) { func (s *Storage) Get(t settings.AuthMethod) (Auther, error) {
auther, err := s.back.Get(t) return s.back.Get(t)
if err != nil {
return nil, err
}
auther.SetStorage(s.users)
return auther, nil
} }
// Save wraps a StorageBackend.Save. // Save wraps a StorageBackend.Save.

View File

@ -30,10 +30,11 @@ var configCmd = &cobra.Command{
} }
func addConfigFlags(cmd *cobra.Command) { func addConfigFlags(cmd *cobra.Command) {
addUserFlags(cmd) addUserFlags(cmd, "defaults.")
cmd.Flags().StringP("baseURL", "b", "/", "base url of this installation") cmd.Flags().StringP("baseURL", "b", "/", "base url of this installation")
cmd.Flags().BoolP("signup", "s", false, "allow users to signup") 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("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("address", "a", "127.0.0.1", "default address to listen to")
cmd.Flags().StringP("log", "l", "stderr", "log output") 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, "Auth method:\t%s\n", s.AuthMethod)
fmt.Fprintf(w, "Shell:\t%s\t\n", strings.Join(s.Shell, " ")) 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, "Log:\t%s\t\n", s.Log)
fmt.Fprintf(w, "Scope:\t%s\t\n", s.Scope)
fmt.Fprintln(w, "\nServer:") fmt.Fprintln(w, "\nServer:")
fmt.Fprintf(w, "\tAddress:\t%s\n", s.Server.Address) fmt.Fprintf(w, "\tAddress:\t%s\n", s.Server.Address)
fmt.Fprintf(w, "\tPort:\t%d\n", s.Server.Port) fmt.Fprintf(w, "\tPort:\t%d\n", s.Server.Port)

View File

@ -15,7 +15,6 @@ func init() {
configCmd.AddCommand(configInitCmd) configCmd.AddCommand(configInitCmd)
rootCmd.AddCommand(configInitCmd) rootCmd.AddCommand(configInitCmd)
addConfigFlags(configInitCmd) addConfigFlags(configInitCmd)
configInitCmd.MarkFlagRequired("scope")
} }
var configInitCmd = &cobra.Command{ var configInitCmd = &cobra.Command{
@ -33,9 +32,16 @@ override the options.`,
} }
defaults := settings.UserDefaults{} defaults := settings.UserDefaults{}
getUserDefaults(cmd, &defaults, true) getUserDefaults(cmd, &defaults, "defaults.", true)
authMethod, auther := getAuthentication(cmd) authMethod, auther := getAuthentication(cmd)
var err error
scope := mustGetString(cmd, "scope")
if scope == "" {
scope, err = os.Getwd()
checkErr(err)
}
db, err := storm.Open(databasePath) db, err := storm.Open(databasePath)
checkErr(err) checkErr(err)
defer db.Close() defer db.Close()
@ -45,6 +51,7 @@ override the options.`,
BaseURL: mustGetString(cmd, "baseURL"), BaseURL: mustGetString(cmd, "baseURL"),
Log: mustGetString(cmd, "log"), Log: mustGetString(cmd, "log"),
Signup: mustGetBool(cmd, "signup"), Signup: mustGetBool(cmd, "signup"),
Scope: scope,
Shell: strings.Split(strings.TrimSpace(mustGetString(cmd, "shell")), " "), Shell: strings.Split(strings.TrimSpace(mustGetString(cmd, "shell")), " "),
AuthMethod: authMethod, AuthMethod: authMethod,
Defaults: defaults, Defaults: defaults,

View File

@ -57,7 +57,7 @@ you want to change.`,
} }
}) })
getUserDefaults(cmd, &s.Defaults, false) getUserDefaults(cmd, &s.Defaults, "defaults.", false)
var auther auth.Auther var auther auth.Auther
if hasAuth { if hasAuth {

View File

@ -3,7 +3,6 @@ package cmd
import ( import (
"crypto/rand" "crypto/rand"
"crypto/tls" "crypto/tls"
"errors"
"io/ioutil" "io/ioutil"
"log" "log"
"net" "net"
@ -35,7 +34,7 @@ func init() {
rootCmd.Flags().IntP("port", "p", 0, "port to listen on (default comes from database)") 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("cert", "c", "", "tls certificate (default comes from database)")
rootCmd.Flags().StringP("key", "k", "", "tls key (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{ var rootCmd = &cobra.Command{
@ -103,9 +102,11 @@ func serverVisitAndReplace(cmd *cobra.Command, s *settings.Settings) {
} }
func quickSetup(cmd *cobra.Command) { func quickSetup(cmd *cobra.Command) {
var err error
scope := mustGetString(cmd, "scope") scope := mustGetString(cmd, "scope")
if 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) db, err := storm.Open(databasePath)
@ -115,6 +116,7 @@ func quickSetup(cmd *cobra.Command) {
set := &settings.Settings{ set := &settings.Settings{
Key: generateRandomBytes(64), // 256 bit Key: generateRandomBytes(64), // 256 bit
BaseURL: "", BaseURL: "",
Scope: scope,
Log: "stderr", Log: "stderr",
Signup: false, Signup: false,
AuthMethod: auth.MethodJSONAuth, AuthMethod: auth.MethodJSONAuth,
@ -125,7 +127,7 @@ func quickSetup(cmd *cobra.Command) {
TLSKey: mustGetString(cmd, "key"), TLSKey: mustGetString(cmd, "key"),
}, },
Defaults: settings.UserDefaults{ Defaults: settings.UserDefaults{
Scope: scope, Scope: ".",
Locale: "en", Locale: "en",
Perm: users.Permissions{ Perm: users.Permissions{
Admin: false, Admin: false,
@ -169,6 +171,13 @@ func startServer(cmd *cobra.Command, st *storage.Storage) {
settings, err := st.Settings.Get() settings, err := st.Settings.Get()
checkErr(err) checkErr(err)
scope := mustGetString(cmd, "scope")
if scope != "" {
settings.Scope = scope
err = st.Settings.Save(settings)
checkErr(err)
}
serverVisitAndReplace(cmd, settings) serverVisitAndReplace(cmd, settings)
setupLogger(settings) setupLogger(settings)

View File

@ -39,7 +39,7 @@ func runRules(cmd *cobra.Command, users func(*users.User, *storage.Storage), glo
id := getUserIdentifier(cmd) id := getUserIdentifier(cmd)
if id != nil { if id != nil {
user, err := st.Users.Get(id) user, err := st.Users.Get("", id)
checkErr(err) checkErr(err)
if users != nil { if users != nil {

View File

@ -64,22 +64,22 @@ func usernameOrIDRequired(cmd *cobra.Command, args []string) error {
return nil return nil
} }
func addUserFlags(cmd *cobra.Command) { func addUserFlags(cmd *cobra.Command, prepend string) {
cmd.Flags().Bool("perm.admin", false, "admin perm for users") cmd.Flags().Bool(prepend+"perm.admin", false, "admin perm for users")
cmd.Flags().Bool("perm.execute", true, "execute perm for users") cmd.Flags().Bool(prepend+"perm.execute", true, "execute perm for users")
cmd.Flags().Bool("perm.create", true, "create perm for users") cmd.Flags().Bool(prepend+"perm.create", true, "create perm for users")
cmd.Flags().Bool("perm.rename", true, "rename perm for users") cmd.Flags().Bool(prepend+"perm.rename", true, "rename perm for users")
cmd.Flags().Bool("perm.modify", true, "modify perm for users") cmd.Flags().Bool(prepend+"perm.modify", true, "modify perm for users")
cmd.Flags().Bool("perm.delete", true, "delete perm for users") cmd.Flags().Bool(prepend+"perm.delete", true, "delete perm for users")
cmd.Flags().Bool("perm.share", true, "share perm for users") cmd.Flags().Bool(prepend+"perm.share", true, "share perm for users")
cmd.Flags().Bool("perm.download", true, "download perm for users") cmd.Flags().Bool(prepend+"perm.download", true, "download perm for users")
cmd.Flags().String("sorting.by", "name", "sorting mode (name, size or modified)") cmd.Flags().String(prepend+"sorting.by", "name", "sorting mode (name, size or modified)")
cmd.Flags().Bool("sorting.asc", false, "sorting by ascending order") cmd.Flags().Bool(prepend+"sorting.asc", false, "sorting by ascending order")
cmd.Flags().Bool("lockPassword", false, "lock password") cmd.Flags().Bool(prepend+"lockPassword", false, "lock password")
cmd.Flags().StringSlice("commands", nil, "a list of the commands a user can execute") cmd.Flags().StringSlice(prepend+"commands", nil, "a list of the commands a user can execute")
cmd.Flags().String("scope", "", "scope for users") cmd.Flags().String(prepend+"scope", "", "scope for users")
cmd.Flags().String("locale", "en", "locale for users") cmd.Flags().String(prepend+"locale", "en", "locale for users")
cmd.Flags().String("viewMode", string(users.ListViewMode), "view mode for users") cmd.Flags().String(prepend+"viewMode", string(users.ListViewMode), "view mode for users")
} }
func getViewMode(cmd *cobra.Command) users.ViewMode { func getViewMode(cmd *cobra.Command) users.ViewMode {
@ -90,39 +90,39 @@ func getViewMode(cmd *cobra.Command) users.ViewMode {
return 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) { visit := func(flag *pflag.Flag) {
switch flag.Name { switch flag.Name {
case "scope": case prepend+"scope":
defaults.Scope = mustGetString(cmd, "scope") defaults.Scope = mustGetString(cmd, flag.Name)
case "locale": case prepend+"locale":
defaults.Locale = mustGetString(cmd, "locale") defaults.Locale = mustGetString(cmd, flag.Name)
case "viewMode": case prepend+"viewMode":
defaults.ViewMode = getViewMode(cmd) defaults.ViewMode = getViewMode(cmd)
case "perm.admin": case prepend+"perm.admin":
defaults.Perm.Admin = mustGetBool(cmd, "perm.admin") defaults.Perm.Admin = mustGetBool(cmd, flag.Name)
case "perm.execute": case prepend+"perm.execute":
defaults.Perm.Execute = mustGetBool(cmd, "perm.execute") defaults.Perm.Execute = mustGetBool(cmd, flag.Name)
case "perm.create": case prepend+"perm.create":
defaults.Perm.Create = mustGetBool(cmd, "perm.create") defaults.Perm.Create = mustGetBool(cmd, flag.Name)
case "perm.rename": case prepend+"perm.rename":
defaults.Perm.Rename = mustGetBool(cmd, "perm.rename") defaults.Perm.Rename = mustGetBool(cmd, flag.Name)
case "perm.modify": case prepend+"perm.modify":
defaults.Perm.Modify = mustGetBool(cmd, "perm.modify") defaults.Perm.Modify = mustGetBool(cmd, flag.Name)
case "perm.delete": case prepend+"perm.delete":
defaults.Perm.Delete = mustGetBool(cmd, "perm.delete") defaults.Perm.Delete = mustGetBool(cmd, flag.Name)
case "perm.share": case prepend+"perm.share":
defaults.Perm.Share = mustGetBool(cmd, "perm.share") defaults.Perm.Share = mustGetBool(cmd, flag.Name)
case "perm.download": case prepend+"perm.download":
defaults.Perm.Download = mustGetBool(cmd, "perm.download") defaults.Perm.Download = mustGetBool(cmd, flag.Name)
case "commands": case prepend+"commands":
commands, err := cmd.Flags().GetStringSlice("commands") commands, err := cmd.Flags().GetStringSlice(flag.Name)
checkErr(err) checkErr(err)
defaults.Commands = commands defaults.Commands = commands
case "sorting.by": case prepend+"sorting.by":
defaults.Sorting.By = mustGetString(cmd, "sorting.by") defaults.Sorting.By = mustGetString(cmd, flag.Name)
case "sorting.asc": case prepend+"sorting.asc":
defaults.Sorting.Asc = mustGetBool(cmd, "sorting.asc") defaults.Sorting.Asc = mustGetBool(cmd, flag.Name)
} }
} }

View File

@ -32,19 +32,21 @@ var findUsers = func(cmd *cobra.Command, args []string) {
defer db.Close() defer db.Close()
st := getStorage(db) st := getStorage(db)
settings, err := st.Settings.Get()
checkErr(err)
username, _ := cmd.Flags().GetString("username") username, _ := cmd.Flags().GetString("username")
id, _ := cmd.Flags().GetUint("id") id, _ := cmd.Flags().GetUint("id")
var err error
var list []*users.User var list []*users.User
var user *users.User var user *users.User
if username != "" { if username != "" {
user, err = st.Users.Get(username) user, err = st.Users.Get(settings.Scope, username)
} else if id != 0 { } else if id != 0 {
user, err = st.Users.Get(id) user, err = st.Users.Get(settings.Scope, id)
} else { } else {
list, err = st.Users.Gets() list, err = st.Users.Gets(settings.Scope)
} }
checkErr(err) checkErr(err)

View File

@ -8,7 +8,7 @@ import (
func init() { func init() {
usersCmd.AddCommand(usersNewCmd) usersCmd.AddCommand(usersNewCmd)
addUserFlags(usersNewCmd) addUserFlags(usersNewCmd, "")
usersNewCmd.Flags().StringP("username", "u", "", "new users's username") usersNewCmd.Flags().StringP("username", "u", "", "new users's username")
usersNewCmd.Flags().StringP("password", "p", "", "new user's password") usersNewCmd.Flags().StringP("password", "p", "", "new user's password")
usersNewCmd.MarkFlagRequired("username") usersNewCmd.MarkFlagRequired("username")
@ -27,7 +27,7 @@ var usersNewCmd = &cobra.Command{
s, err := st.Settings.Get() s, err := st.Settings.Get()
checkErr(err) checkErr(err)
getUserDefaults(cmd, &s.Defaults, false) getUserDefaults(cmd, &s.Defaults, "", false)
password, _ := cmd.Flags().GetString("password") password, _ := cmd.Flags().GetString("password")
password, err = users.HashPwd(password) password, err = users.HashPwd(password)

View File

@ -12,7 +12,7 @@ func init() {
usersUpdateCmd.Flags().UintP("id", "i", 0, "id of the user") 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("username", "u", "", "user to change or new username if flag 'id' is set")
usersUpdateCmd.Flags().StringP("password", "p", "", "new password") usersUpdateCmd.Flags().StringP("password", "p", "", "new password")
addUserFlags(usersUpdateCmd) addUserFlags(usersUpdateCmd, "")
} }
var usersUpdateCmd = &cobra.Command{ var usersUpdateCmd = &cobra.Command{
@ -26,17 +26,19 @@ options you want to change.`,
defer db.Close() defer db.Close()
st := getStorage(db) st := getStorage(db)
set, err := st.Settings.Get()
checkErr(err)
id, _ := cmd.Flags().GetUint("id") id, _ := cmd.Flags().GetUint("id")
username := mustGetString(cmd, "username") username := mustGetString(cmd, "username")
password := mustGetString(cmd, "password") password := mustGetString(cmd, "password")
var user *users.User var user *users.User
var err error
if id != 0 { if id != 0 {
user, err = st.Users.Get(id) user, err = st.Users.Get(set.Scope, id)
} else { } else {
user, err = st.Users.Get(username) user, err = st.Users.Get(set.Scope, username)
} }
checkErr(err) checkErr(err)
@ -49,7 +51,7 @@ options you want to change.`,
Sorting: user.Sorting, Sorting: user.Sorting,
Commands: user.Commands, Commands: user.Commands,
} }
getUserDefaults(cmd, &defaults, false) getUserDefaults(cmd, &defaults, "", false)
user.Scope = defaults.Scope user.Scope = defaults.Scope
user.Locale = defaults.Locale user.Locale = defaults.Locale
user.ViewMode = defaults.ViewMode user.ViewMode = defaults.ViewMode

View File

@ -67,7 +67,7 @@ func withUser(fn handleFunc) handleFunc {
w.Header().Add("X-Renew-Token", "true") 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 { if err != nil {
return http.StatusInternalServerError, err 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 return http.StatusInternalServerError, err
} }
user, err := auther.Auth(r) user, err := auther.Auth(r, d.store.Users, d.Settings)
if err == os.ErrPermission { if err == os.ErrPermission {
return http.StatusForbidden, nil return http.StatusForbidden, nil
} else if err != nil { } else if err != nil {

View File

@ -13,7 +13,7 @@ var withHashFile = func(fn handleFunc) handleFunc {
return errToStatus(err), err 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 { if err != nil {
return errToStatus(err), err return errToStatus(err), err
} }

View File

@ -61,7 +61,7 @@ func withSelfOrAdmin(fn handleFunc) handleFunc {
} }
var usersGetHandler = withAdmin(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { 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 { if err != nil {
return http.StatusInternalServerError, err 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) { 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 { if err == errors.ErrNotExist {
return http.StatusNotFound, err 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) req.Data.Password, err = users.HashPwd(req.Data.Password)
} else { } else {
var suser *users.User 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 req.Data.Password = suser.Password
} }

View File

@ -10,6 +10,7 @@ type Settings struct {
Key []byte `json:"key"` Key []byte `json:"key"`
BaseURL string `json:"baseURL"` BaseURL string `json:"baseURL"`
Log string `json:"log"` Log string `json:"log"`
Scope string `json:"scope"`
Server Server `json:"server"` Server Server `json:"server"`
Signup bool `json:"signup"` Signup bool `json:"signup"`
Defaults UserDefaults `json:"defaults"` Defaults UserDefaults `json:"defaults"`

View File

@ -3,7 +3,7 @@ package importer
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"path/filepath" "os"
"github.com/asdine/storm" "github.com/asdine/storm"
"github.com/filebrowser/filebrowser/v2/rules" "github.com/filebrowser/filebrowser/v2/rules"
@ -52,7 +52,6 @@ func readOldUsers(db *storm.DB) ([]*oldUser, error) {
} }
func convertUsersToNew(old []*oldUser) ([]*users.User, error) { func convertUsersToNew(old []*oldUser) ([]*users.User, error) {
var err error
list := []*users.User{} list := []*users.User{}
for _, oldUser := range old { for _, oldUser := range old {
@ -82,12 +81,12 @@ func convertUsersToNew(old []*oldUser) ([]*users.User, error) {
user.Rules = append(user.Rules, *rule) user.Rules = append(user.Rules, *rule)
} }
user.Scope, err = filepath.Abs(user.Scope) baseScope, err := os.Getwd()
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = user.Clean() err = user.Clean(baseScope)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -36,7 +36,7 @@ func NewStorage(back StorageBackend) *Storage {
// Get allows you to get a user by its name or username. The provided // 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 // id must be a string for username lookup or a uint for id lookup. If id
// is neither, a ErrInvalidDataType will be returned. // 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 ( var (
user *User user *User
err error err error
@ -55,19 +55,19 @@ func (s *Storage) Get(id interface{}) (*User, error) {
return nil, err return nil, err
} }
user.Clean() user.Clean(baseScope)
return user, err return user, err
} }
// Gets gets a list of all users. // 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() users, err := s.back.Gets()
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, user := range users { for _, user := range users {
user.Clean() user.Clean(baseScope)
} }
return users, err return users, err
@ -75,7 +75,7 @@ func (s *Storage) Gets() ([]*User, error) {
// Update updates a user in the database. // Update updates a user in the database.
func (s *Storage) Update(user *User, fields ...string) error { func (s *Storage) Update(user *User, fields ...string) error {
err := user.Clean(fields...) err := user.Clean("", fields...)
if err != nil { if err != nil {
return err return err
} }
@ -93,7 +93,7 @@ func (s *Storage) Update(user *User, fields ...string) error {
// Save saves the user in a storage. // Save saves the user in a storage.
func (s *Storage) Save(user *User) error { func (s *Storage) Save(user *User) error {
if err := user.Clean(); err != nil { if err := user.Clean(""); err != nil {
return err return err
} }

View File

@ -1,10 +1,11 @@
package users package users
import ( import (
"github.com/filebrowser/filebrowser/v2/errors"
"path/filepath" "path/filepath"
"regexp" "regexp"
"github.com/filebrowser/filebrowser/v2/errors"
"github.com/filebrowser/filebrowser/v2/files" "github.com/filebrowser/filebrowser/v2/files"
"github.com/filebrowser/filebrowser/v2/rules" "github.com/filebrowser/filebrowser/v2/rules"
"github.com/spf13/afero" "github.com/spf13/afero"
@ -51,7 +52,7 @@ var checkableFields = []string{
// Clean cleans up a user and verifies if all its fields // Clean cleans up a user and verifies if all its fields
// are alright to be saved. // 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 { if len(fields) == 0 {
fields = checkableFields fields = checkableFields
} }
@ -66,10 +67,6 @@ func (u *User) Clean(fields ...string) error {
if u.Password == "" { if u.Password == "" {
return errors.ErrEmptyPassword return errors.ErrEmptyPassword
} }
case "Scope":
if !filepath.IsAbs(u.Scope) {
return errors.ErrScopeIsRelative
}
case "ViewMode": case "ViewMode":
if u.ViewMode == "" { if u.ViewMode == "" {
u.ViewMode = ListViewMode u.ViewMode = ListViewMode
@ -90,7 +87,13 @@ func (u *User) Clean(fields ...string) error {
} }
if u.Fs == nil { 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 return nil