diff --git a/auth/json.go b/auth/json.go index 2fb81f95..696be5b9 100644 --- a/auth/json.go +++ b/auth/json.go @@ -21,7 +21,7 @@ type jsonCred struct { // JSONAuth is a json implementaion of an auther. type JSONAuth struct { ReCaptcha *ReCaptcha - Store types.UsersStore `json:"-"` + Store *types.UsersVerify `json:"-"` } // Auth authenticates the user via a json in content body. diff --git a/auth/none.go b/auth/none.go index cc53f782..4bf08f89 100644 --- a/auth/none.go +++ b/auth/none.go @@ -11,7 +11,7 @@ const MethodNoAuth types.AuthMethod = "noauth" // NoAuth is no auth implementation of auther. type NoAuth struct { - Store types.UsersStore `json:"-"` + Store *types.UsersVerify `json:"-"` } // Auth uses authenticates user 1. diff --git a/auth/proxy.go b/auth/proxy.go index 0d3673c0..07c8e4d9 100644 --- a/auth/proxy.go +++ b/auth/proxy.go @@ -12,7 +12,7 @@ const MethodProxyAuth types.AuthMethod = "proxy" // ProxyAuth is a proxy implementation of an auther. type ProxyAuth struct { Header string - Store types.UsersStore `json:"-"` + Store *types.UsersVerify `json:"-"` } // Auth authenticates the user via an HTTP header. diff --git a/bolt/config.go b/bolt/config.go index 2a715610..9941975d 100644 --- a/bolt/config.go +++ b/bolt/config.go @@ -8,8 +8,8 @@ import ( // ConfigStore is a configuration store. type ConfigStore struct { - DB *storm.DB - Users types.UsersStore + DB *storm.DB + Users *types.UsersVerify } // Get gets a configuration from the database to an interface. @@ -45,7 +45,7 @@ func (c ConfigStore) GetRunner() (*types.Runner, error) { } // SaveRunner is an helper method to set the runner object -func (c ConfigStore) SaveRunner (r *types.Runner) error { +func (c ConfigStore) SaveRunner(r *types.Runner) error { return c.Save("runner", r) } @@ -56,7 +56,7 @@ func (c ConfigStore) GetAuther(t types.AuthMethod) (types.Auther, error) { if err := c.Get("auther", &auther); err != nil { return nil, err } - auther.Store = &UsersStore{DB: c.DB} + auther.Store = &types.UsersVerify{Store: &UsersStore{DB: c.DB}} return &auther, nil } diff --git a/bolt/users.go b/bolt/users.go index f0185063..e3f7a2d6 100644 --- a/bolt/users.go +++ b/bolt/users.go @@ -22,7 +22,6 @@ func (st UsersStore) Get(id uint) (*types.User, error) { return nil, err } - user.BuildFs() return user, nil } @@ -37,7 +36,6 @@ func (st UsersStore) GetByUsername(username string) (*types.User, error) { return nil, err } - user.BuildFs() return user, nil } @@ -52,10 +50,6 @@ func (st UsersStore) Gets() ([]*types.User, error) { return users, err } - for _, user := range users { - user.BuildFs() - } - return users, err } diff --git a/cmd/root.go b/cmd/root.go index 81f4f772..3ba9036f 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -65,10 +65,12 @@ listening on loalhost on a random port. Use the flags to change it.`, db := getDB() defer db.Close() + usersStore := &types.UsersVerify{Store: bolt.UsersStore{DB: db}} + env := &fhttp.Env{ Store: &types.Store{ - Users: bolt.UsersStore{DB: db}, - Config: bolt.ConfigStore{DB: db, Users: bolt.UsersStore{DB: db}}, + Users: usersStore, + Config: bolt.ConfigStore{DB: db, Users: usersStore}, Share: bolt.ShareStore{DB: db}, }, } diff --git a/types/errors.go b/types/errors.go index 36f94b23..7f30e733 100644 --- a/types/errors.go +++ b/types/errors.go @@ -14,6 +14,7 @@ var ( ErrWrongDataType = errors.New("wrong data type") ErrInvalidUpdateField = errors.New("invalid field to update") ErrInvalidOption = errors.New("invalid option") + ErrPathIsRel = errors.New("path is relative") ErrNoPermission = errors.New("permission denied") ErrInvalidAuthMethod = errors.New("invalid auth method") ) diff --git a/types/storage.go b/types/storage.go index 7de31b61..42a3f84b 100644 --- a/types/storage.go +++ b/types/storage.go @@ -2,23 +2,13 @@ package types // Store is used to persist data. type Store struct { - Users UsersStore + Users *UsersVerify Config ConfigStore Share ShareStore } // TODO: wrappers to verify -// UsersStore is used to manage users relativey to a data storage. -type UsersStore interface { - Get(id uint) (*User, error) - GetByUsername(username string) (*User, error) - Gets() ([]*User, error) - Save(u *User) error - Update(u *User, fields ...string) error - Delete(id uint) error -} - // ConfigStore is used to manage configurations relativey to a data storage. type ConfigStore interface { Get(name string, to interface{}) error diff --git a/types/storage_users.go b/types/storage_users.go new file mode 100644 index 00000000..b3ecd81a --- /dev/null +++ b/types/storage_users.go @@ -0,0 +1,82 @@ +package types + +// UsersStore is used to manage users relativey to a data storage. +type UsersStore interface { + Get(id uint) (*User, error) + GetByUsername(username string) (*User, error) + Gets() ([]*User, error) + Save(u *User) error + Update(u *User, fields ...string) error + Delete(id uint) error + DeleteByUsername(username string) error +} + +// UsersVerify wraps a UsersStore and makes the verifications needed. +type UsersVerify struct { + Store UsersStore +} + +// Get wraps a UsersStore.Get to verify if everything is right. +func (v UsersVerify) Get(id uint) (*User, error) { + user, err := v.Store.Get(id) + if err != nil { + return nil, err + } + + user.clean() + return user, nil +} + +// GetByUsername wraps a UsersStore.GetByUsername to verify if everything is right. +func (v UsersVerify) GetByUsername(username string) (*User, error) { + user, err := v.Store.GetByUsername(username) + if err != nil { + return nil, err + } + + user.clean() + return user, nil +} + +// Gets wraps a UsersStore.Gets to verify if everything is right. +func (v UsersVerify) Gets() ([]*User, error) { + users, err := v.Store.Gets() + if err != nil { + return nil, err + } + + for _, user := range users { + user.clean() + } + + return users, err +} + +// Update wraps a UsersStore.Update to verify if everything is right. +func (v UsersVerify) Update(user *User, fields ...string) error { + err := user.clean(fields...) + if err != nil { + return err + } + + return v.Store.Update(user, fields...) +} + +// Save wraps a UsersStore.Save to verify if everything is right. +func (v UsersVerify) Save(user *User) error { + if err := user.clean(); err != nil { + return err + } + + return v.Store.Save(user) +} + +// Delete wraps a UsersStore.Delete to verify if everything is right. +func (v UsersVerify) Delete(id uint) error { + return v.Store.Delete(id) +} + +// DeleteByUsername wraps a UsersStore.DeleteByUsername to verify if everything is right. +func (v UsersVerify) DeleteByUsername(username string) error { + return v.Store.DeleteByUsername(username) +} diff --git a/types/user.go b/types/user.go index 6bc43698..f54030d5 100644 --- a/types/user.go +++ b/types/user.go @@ -1,6 +1,8 @@ package types import ( + "path/filepath" + "github.com/spf13/afero" "golang.org/x/crypto/bcrypt" ) @@ -41,12 +43,59 @@ type User struct { Rules []Rule `json:"rules"` } -// BuildFs builds the FileSystem property of the user, -// which is the only one that can't be directly stored. -func (u *User) BuildFs() { +var checkableFields = []string{ + "Username", + "Password", + "Scope", + "ViewMode", + "Commands", + "Sorting", + "Rules", +} + +func (u *User) clean(fields ...string) error { + if len(fields) == 0 { + fields = checkableFields + } + + for _, field := range fields { + switch field { + case "Username": + if u.Username == "" { + return ErrEmptyUsername + } + case "Password": + if u.Password == "" { + return ErrEmptyPassword + } + case "Scope": + if !filepath.IsAbs(u.Scope) { + return ErrPathIsRel + } + case "ViewMode": + if u.ViewMode == "" { + u.ViewMode = ListViewMode + } + case "Commands": + if u.Commands == nil { + u.Commands = []string{} + } + case "Sorting": + if u.Sorting.By == "" { + u.Sorting.By = "name" + } + case "Rules": + if u.Rules == nil { + u.Rules = []Rule{} + } + } + } + if u.Fs == nil { u.Fs = afero.NewBasePathFs(afero.NewOsFs(), u.Scope) } + + return nil } // IsAllowed checks if an user is allowed to go to a certain path.