some cleaning

License: MIT
Signed-off-by: Henrique Dias <hacdias@gmail.com>
This commit is contained in:
Henrique Dias 2019-01-03 14:06:03 +00:00
parent 94cec714ce
commit f3c1c4b5d2
37 changed files with 492 additions and 376 deletions

View File

@ -18,14 +18,14 @@ type jsonCred struct {
ReCaptcha string `json:"recaptcha"`
}
// JSONAuth is a json implementaion of an auther.
// JSONAuth is a json implementaion of an Auther.
type JSONAuth struct {
ReCaptcha *ReCaptcha
Store *types.UsersVerify `json:"-"`
store *types.Storage
}
// Auth authenticates the user via a json in content body.
func (a JSONAuth) Auth(r *http.Request) (*types.User, error) {
func (a *JSONAuth) Auth(r *http.Request) (*types.User, error) {
var cred jsonCred
if r.Body == nil {
@ -50,7 +50,7 @@ func (a JSONAuth) Auth(r *http.Request) (*types.User, error) {
}
}
u, err := a.Store.GetByUsername(cred.Username)
u, err := a.store.GetUser(cred.Username)
if err != nil || !types.CheckPwd(cred.Password, u.Password) {
return nil, types.ErrNoPermission
}
@ -58,6 +58,11 @@ func (a JSONAuth) Auth(r *http.Request) (*types.User, error) {
return u, nil
}
// SetStorage attaches the storage information to the auther.
func (a *JSONAuth) SetStorage(s *types.Storage) {
a.store = s
}
const reCaptchaAPI = "/recaptcha/api/siteverify"
// ReCaptcha identifies a recaptcha conenction.

View File

@ -11,10 +11,15 @@ const MethodNoAuth types.AuthMethod = "noauth"
// NoAuth is no auth implementation of auther.
type NoAuth struct {
Store *types.UsersVerify `json:"-"`
store *types.Storage
}
// Auth uses authenticates user 1.
func (a NoAuth) Auth(r *http.Request) (*types.User, error) {
return a.Store.Get(1)
func (a *NoAuth) Auth(r *http.Request) (*types.User, error) {
return a.store.GetUser(1)
}
// SetStorage attaches the storage information to the auther.
func (a *NoAuth) SetStorage(s *types.Storage) {
a.store = s
}

View File

@ -12,16 +12,21 @@ const MethodProxyAuth types.AuthMethod = "proxy"
// ProxyAuth is a proxy implementation of an auther.
type ProxyAuth struct {
Header string
Store *types.UsersVerify `json:"-"`
store *types.Storage
}
// Auth authenticates the user via an HTTP header.
func (a ProxyAuth) Auth(r *http.Request) (*types.User, error) {
func (a *ProxyAuth) Auth(r *http.Request) (*types.User, error) {
username := r.Header.Get(a.Header)
user, err := a.Store.GetByUsername(username)
user, err := a.store.GetUser(username)
if err == types.ErrNotExist {
return nil, types.ErrNoPermission
}
return user, err
}
// SetStorage attaches the storage information to the auther.
func (a *ProxyAuth) SetStorage(s *types.Storage) {
a.store = s
}

View File

@ -2,11 +2,7 @@ package bolt
import "github.com/asdine/storm"
func Open(path string) (*storm.DB, error) {
db, err := storm.Open(path)
if err != nil {
return nil, err
}
return db, nil
// Backend implements types.StorageBackend.
type Backend struct {
DB *storm.DB
}

View File

@ -6,15 +6,8 @@ import (
"github.com/filebrowser/filebrowser/types"
)
// ConfigStore is a configuration store.
type ConfigStore struct {
DB *storm.DB
Users *types.UsersVerify
}
// Get gets a configuration from the database to an interface.
func (c ConfigStore) Get(name string, to interface{}) error {
err := c.DB.Get("config", name, to)
func (b Backend) get(name string, to interface{}) error {
err := b.DB.Get("config", name, to)
if err == storm.ErrNotFound {
return types.ErrNotExist
}
@ -22,53 +15,36 @@ func (c ConfigStore) Get(name string, to interface{}) error {
return err
}
// Save saves a configuration from an interface to the database.
func (c ConfigStore) Save(name string, from interface{}) error {
return c.DB.Set("config", name, from)
func (b Backend) save(name string, from interface{}) error {
return b.DB.Set("config", name, from)
}
// GetSettings is an helper method to get a settings object.
func (c ConfigStore) GetSettings() (*types.Settings, error) {
func (b Backend) GetSettings() (*types.Settings, error) {
settings := &types.Settings{}
return settings, c.Get("settings", settings)
return settings, b.get("settings", settings)
}
// SaveSettings is an helper method to set the settings object
func (c ConfigStore) SaveSettings(s *types.Settings) error {
return c.Save("settings", s)
func (b Backend) SaveSettings(s *types.Settings) error {
return b.save("settings", s)
}
// GetAuther is an helper method to get an auther object.
func (c ConfigStore) GetAuther(t types.AuthMethod) (types.Auther, error) {
if t == auth.MethodJSONAuth {
auther := auth.JSONAuth{}
if err := c.Get("auther", &auther); err != nil {
return nil, err
}
auther.Store = &types.UsersVerify{Store: &UsersStore{DB: c.DB}}
return &auther, nil
}
if t == auth.MethodProxyAuth {
auther := auth.ProxyAuth{}
if err := c.Get("auther", &auther); err != nil {
return nil, err
}
return &auther, nil
}
if t == auth.MethodNoAuth {
auther := auth.NoAuth{Store: c.Users}
if err := c.Get("auther", &auther); err != nil {
return nil, err
}
return &auther, nil
}
func (b Backend) GetAuther(t types.AuthMethod) (types.Auther, error) {
var auther types.Auther
switch t {
case auth.MethodJSONAuth:
auther = &auth.JSONAuth{}
case auth.MethodProxyAuth:
auther = &auth.ProxyAuth{}
case auth.MethodNoAuth:
auther = &auth.NoAuth{}
default:
return nil, types.ErrInvalidAuthMethod
}
return auther, b.get("auther", auther)
}
// SaveAuther is an helper method to set the auther object
func (c ConfigStore) SaveAuther(a types.Auther) error {
return c.Save("auther", a)
func (b Backend) SaveAuther(a types.Auther) error {
return b.save("auther", a)
}

View File

@ -6,13 +6,7 @@ import (
"github.com/filebrowser/filebrowser/types"
)
// ShareStore is a shareable links store.
type ShareStore struct {
DB *storm.DB
}
// Get gets a Share Link from an hash.
func (s ShareStore) Get(hash string) (*types.ShareLink, error) {
func (s Backend) GetLinkByHash(hash string) (*types.ShareLink, error) {
var v types.ShareLink
err := s.DB.One("Hash", hash, &v)
if err == storm.ErrNotFound {
@ -22,8 +16,7 @@ func (s ShareStore) Get(hash string) (*types.ShareLink, error) {
return &v, err
}
// GetPermanent gets the permanent link from a path.
func (s ShareStore) GetPermanent(path string) (*types.ShareLink, error) {
func (s Backend) GetLinkPermanent(path string) (*types.ShareLink, error) {
var v types.ShareLink
err := s.DB.Select(q.Eq("Path", path), q.Eq("Expires", false)).First(&v)
if err == storm.ErrNotFound {
@ -33,8 +26,7 @@ func (s ShareStore) GetPermanent(path string) (*types.ShareLink, error) {
return &v, err
}
// GetByPath gets all the links for a specific path.
func (s ShareStore) GetByPath(hash string) ([]*types.ShareLink, error) {
func (s Backend) GetLinksByPath(hash string) ([]*types.ShareLink, error) {
var v []*types.ShareLink
err := s.DB.Find("Path", hash, &v)
if err == storm.ErrNotFound {
@ -44,23 +36,10 @@ func (s ShareStore) GetByPath(hash string) ([]*types.ShareLink, error) {
return v, err
}
// Gets retrieves all the shareable links.
func (s ShareStore) Gets() ([]*types.ShareLink, error) {
var v []*types.ShareLink
err := s.DB.All(&v)
if err == storm.ErrNotFound {
return v, types.ErrNotExist
}
return v, err
}
// Save stores a Share Link on the database.
func (s ShareStore) Save(l *types.ShareLink) error {
func (s Backend) SaveLink(l *types.ShareLink) error {
return s.DB.Save(l)
}
// Delete deletes a Share Link from the database.
func (s ShareStore) Delete(hash string) error {
func (s Backend) DeleteLink(hash string) error {
return s.DB.DeleteStruct(&types.ShareLink{Hash: hash})
}

View File

@ -7,11 +7,7 @@ import (
"github.com/filebrowser/filebrowser/types"
)
type UsersStore struct {
DB *storm.DB
}
func (st UsersStore) Get(id uint) (*types.User, error) {
func (st Backend) GetUserByID(id uint) (*types.User, error) {
user := &types.User{}
err := st.DB.One("ID", id, user)
if err == storm.ErrNotFound {
@ -25,7 +21,7 @@ func (st UsersStore) Get(id uint) (*types.User, error) {
return user, nil
}
func (st UsersStore) GetByUsername(username string) (*types.User, error) {
func (st Backend) GetUserByUsername(username string) (*types.User, error) {
user := &types.User{}
err := st.DB.One("Username", username, user)
if err == storm.ErrNotFound {
@ -39,7 +35,7 @@ func (st UsersStore) GetByUsername(username string) (*types.User, error) {
return user, nil
}
func (st UsersStore) Gets() ([]*types.User, error) {
func (st Backend) GetUsers() ([]*types.User, error) {
users := []*types.User{}
err := st.DB.All(&users)
if err == storm.ErrNotFound {
@ -53,9 +49,9 @@ func (st UsersStore) Gets() ([]*types.User, error) {
return users, err
}
func (st UsersStore) Update(user *types.User, fields ...string) error {
func (st Backend) UpdateUser(user *types.User, fields ...string) error {
if len(fields) == 0 {
return st.Save(user)
return st.SaveUser(user)
}
for _, field := range fields {
@ -68,7 +64,7 @@ func (st UsersStore) Update(user *types.User, fields ...string) error {
return nil
}
func (st UsersStore) Save(user *types.User) error {
func (st Backend) SaveUser(user *types.User) error {
err := st.DB.Save(user)
if err == storm.ErrAlreadyExists {
return types.ErrExist
@ -76,12 +72,12 @@ func (st UsersStore) Save(user *types.User) error {
return err
}
func (st UsersStore) Delete(id uint) error {
func (st Backend) DeleteUserByID(id uint) error {
return st.DB.DeleteStruct(&types.User{ID: id})
}
func (st UsersStore) DeleteByUsername(username string) error {
user, err := st.GetByUsername(username)
func (st Backend) DeleteUserByUsername(username string) error {
user, err := st.GetUserByUsername(username)
if err != nil {
return err
}

View File

@ -21,14 +21,14 @@ var cmdsAddCmd = &cobra.Command{
db := getDB()
defer db.Close()
st := getStore(db)
s, err := st.Config.GetSettings()
s, err := st.GetSettings()
checkErr(err)
evt := mustGetString(cmd, "event")
command := mustGetString(cmd, "command")
s.Commands[evt] = append(s.Commands[evt], command)
err = st.Config.SaveSettings(s)
err = st.SaveSettings(s)
checkErr(err)
printEvents(s.Commands)
},

View File

@ -18,7 +18,7 @@ var cmdsLsCmd = &cobra.Command{
db := getDB()
defer db.Close()
st := getStore(db)
s, err := st.Config.GetSettings()
s, err := st.GetSettings()
checkErr(err)
evt := mustGetString(cmd, "event")

View File

@ -21,7 +21,7 @@ var cmdsRmCmd = &cobra.Command{
db := getDB()
defer db.Close()
st := getStore(db)
s, err := st.Config.GetSettings()
s, err := st.GetSettings()
checkErr(err)
evt := mustGetString(cmd, "event")
@ -29,7 +29,7 @@ var cmdsRmCmd = &cobra.Command{
checkErr(err)
s.Commands[evt] = append(s.Commands[evt][:i], s.Commands[evt][i+1:]...)
err = st.Config.SaveSettings(s)
err = st.SaveSettings(s)
checkErr(err)
printEvents(s.Commands)
},

View File

@ -55,15 +55,15 @@ func getAuthentication(cmd *cobra.Command) (types.AuthMethod, types.Auther) {
if header == "" {
panic(errors.New("you must set the flag 'auth.header' for method 'proxy'"))
}
auther = auth.ProxyAuth{Header: header}
auther = &auth.ProxyAuth{Header: header}
}
if method == auth.MethodNoAuth {
auther = auth.NoAuth{}
auther = &auth.NoAuth{}
}
if method == auth.MethodJSONAuth {
jsonAuth := auth.JSONAuth{}
jsonAuth := &auth.JSONAuth{}
host := mustGetString(cmd, "recaptcha.host")
key := mustGetString(cmd, "recaptcha.key")

View File

@ -17,9 +17,9 @@ var configCatCmd = &cobra.Command{
db := getDB()
defer db.Close()
st := getStore(db)
s, err := st.Config.GetSettings()
s, err := st.GetSettings()
checkErr(err)
auther, err := st.Config.GetAuther(s.AuthMethod)
auther, err := st.GetAuther(s.AuthMethod)
checkErr(err)
printSettings(s, auther)
},

View File

@ -7,7 +7,6 @@ import (
"strings"
"github.com/asdine/storm"
"github.com/filebrowser/filebrowser/bolt"
"github.com/filebrowser/filebrowser/types"
"github.com/spf13/cobra"
)
@ -51,7 +50,7 @@ override the options.`,
},
}
db, err := bolt.Open(databasePath)
db, err := storm.Open(databasePath)
checkErr(err)
defer db.Close()
@ -68,8 +67,8 @@ need to call the main command to boot up the server.
func saveConfig(db *storm.DB, s *types.Settings, a types.Auther) {
st := getStore(db)
err := st.Config.SaveSettings(s)
err := st.SaveSettings(s)
checkErr(err)
err = st.Config.SaveAuther(a)
err = st.SaveAuther(a)
checkErr(err)
}

View File

@ -24,7 +24,7 @@ you want to change.`,
defer db.Close()
st := getStore(db)
s, err := st.Config.GetSettings()
s, err := st.GetSettings()
checkErr(err)
auth := false
@ -52,14 +52,14 @@ you want to change.`,
var auther types.Auther
if auth {
s.AuthMethod, auther = getAuthentication(cmd)
err = st.Config.SaveAuther(auther)
err = st.SaveAuther(auther)
checkErr(err)
} else {
auther, err = st.Config.GetAuther(s.AuthMethod)
auther, err = st.GetAuther(s.AuthMethod)
checkErr(err)
}
err = st.Config.SaveSettings(s)
err = st.SaveSettings(s)
checkErr(err)
printSettings(s, auther)
},

View File

@ -10,8 +10,8 @@ import (
"os"
"strconv"
"github.com/asdine/storm"
"github.com/filebrowser/filebrowser/auth"
"github.com/filebrowser/filebrowser/bolt"
"github.com/filebrowser/filebrowser/types"
fhttp "github.com/filebrowser/filebrowser/http"
@ -61,9 +61,9 @@ listening on loalhost on a random port. Use the flags to change it.`,
Store: getStore(db),
}
env.Settings, err = env.Store.Config.GetSettings()
env.Settings, err = env.Store.GetSettings()
checkErr(err)
env.Auther, err = env.Store.Config.GetAuther(env.Settings.AuthMethod)
env.Auther, err = env.Store.GetAuther(env.Settings.AuthMethod)
checkErr(err)
startServer(cmd, env)
@ -127,14 +127,14 @@ func quickSetup(cmd *cobra.Command) {
user.ApplyDefaults(settings.Defaults)
user.Perm.Admin = true
db, err := bolt.Open(databasePath)
db, err := storm.Open(databasePath)
checkErr(err)
defer db.Close()
saveConfig(db, settings, &auth.JSONAuth{})
st := getStore(db)
err = st.Users.Save(user)
err = st.SaveUser(user)
checkErr(err)
}

View File

@ -40,11 +40,11 @@ var findUsers = func(cmd *cobra.Command, args []string) {
var user *types.User
if username != "" {
user, err = st.Users.GetByUsername(username)
user, err = st.GetUser(username)
} else if id != 0 {
user, err = st.Users.Get(id)
user, err = st.GetUser(id)
} else {
users, err = st.Users.Gets()
users, err = st.GetUsers()
}
checkErr(err)

View File

@ -25,7 +25,7 @@ var usersNewCmd = &cobra.Command{
defer db.Close()
st := getStore(db)
settings, err := st.Config.GetSettings()
settings, err := st.GetSettings()
checkErr(err)
getUserDefaults(cmd, &settings.Defaults, false)
@ -41,7 +41,7 @@ var usersNewCmd = &cobra.Command{
user.ApplyDefaults(settings.Defaults)
err = st.Users.Save(user)
err = st.SaveUser(user)
checkErr(err)
printUsers([]*types.User{user})
},

View File

@ -28,9 +28,9 @@ var usersRmCmd = &cobra.Command{
var err error
if username != "" {
err = st.Users.DeleteByUsername(username)
err = st.DeleteUser(username)
} else {
err = st.Users.Delete(id)
err = st.DeleteUser(id)
}
checkErr(err)

View File

@ -33,9 +33,9 @@ options you want to change.`,
var err error
if id != 0 {
user, err = st.Users.Get(id)
user, err = st.GetUser(id)
} else {
user, err = st.Users.GetByUsername(username)
user, err = st.GetUser(username)
}
checkErr(err)
@ -66,7 +66,7 @@ options you want to change.`,
checkErr(err)
}
err = st.Users.Update(user)
err = st.UpdateUser(user)
checkErr(err)
printUsers([]*types.User{user})
},

View File

@ -34,30 +34,13 @@ func getDB() *storm.DB {
panic(errors.New(databasePath + " does not exist. Please run 'filebrowser init' first."))
}
db, err := bolt.Open(databasePath)
db, err := storm.Open(databasePath)
checkErr(err)
return db
}
func getStore(db *storm.DB) *types.Store {
usersStore := &types.UsersVerify{
Store: bolt.UsersStore{
DB: db,
},
}
configSore := &types.ConfigVerify{
Store: bolt.ConfigStore{
DB: db,
Users: usersStore,
},
}
return &types.Store{
Users: usersStore,
Config: configSore,
Share: bolt.ShareStore{DB: db},
}
func getStore(db *storm.DB) *types.Storage {
return types.NewStorage(&bolt.Backend{DB: db})
}
func generateRandomBytes(n int) []byte {

View File

@ -67,7 +67,7 @@ func (e *Env) signupHandler(w http.ResponseWriter, r *http.Request) {
}
user.Password = pwd
err = e.Store.Users.Save(user)
err = e.Store.SaveUser(user)
if err == types.ErrExist {
httpErr(w, r, http.StatusConflict, nil)
return
@ -133,7 +133,7 @@ func (e *Env) auth(next http.HandlerFunc) http.HandlerFunc {
}
if !tk.VerifyExpiresAt(time.Now().Add(time.Hour).Unix(), true) {
// TODO: chek if user info was modified
// TODO: chek if user info was modified use timestap
w.Header().Add("X-Renew-Token", "true")
}

View File

@ -8,13 +8,14 @@ import (
"sync"
"time"
"github.com/gorilla/websocket"
"github.com/filebrowser/filebrowser/types"
"github.com/gorilla/mux"
"github.com/gorilla/websocket"
)
type key int
const (
keyUserID key = iota
)
@ -28,7 +29,7 @@ type modifyRequest struct {
type Env struct {
Auther types.Auther
Settings *types.Settings
Store *types.Store
Store *types.Storage
mux sync.RWMutex // settings mutex for Settings changes.
}
@ -104,7 +105,7 @@ func renderJSON(w http.ResponseWriter, r *http.Request, data interface{}) {
func (e *Env) getUser(w http.ResponseWriter, r *http.Request) (*types.User, bool) {
id := r.Context().Value(keyUserID).(uint)
user, err := e.Store.Users.Get(id)
user, err := e.Store.GetUser(id)
if err == types.ErrNotExist {
httpErr(w, r, http.StatusForbidden, nil)
return nil, false

View File

@ -28,9 +28,6 @@ func parseQueryFiles(r *http.Request, f *types.File, u *types.User) ([]string, e
}
name = fileutils.SlashClean(name)
if !u.IsAllowed(name) {
continue
}
files = append(files, filepath.Join(f.Path, name))
}
}
@ -70,7 +67,7 @@ func (e *Env) rawHandler(w http.ResponseWriter, r *http.Request) {
return
}
file, err := types.NewFileInfo(user, path)
file, err := types.NewFile(user, path)
if err != nil {
httpErr(w, r, httpFsErr(err), err)
return

View File

@ -42,10 +42,10 @@ func (e *Env) getResourceData(w http.ResponseWriter, r *http.Request, prefix str
path = "/"
}
if !user.IsAllowed(path) {
/* TODO if !user.IsAllowed(path) {
httpErr(w, r, http.StatusForbidden, nil)
return "", nil, false
}
} */
return path, user, true
}
@ -56,7 +56,7 @@ func (e *Env) resourceGetHandler(w http.ResponseWriter, r *http.Request) {
return
}
file, err := types.NewFileInfo(user, path)
file, err := types.NewFile(user, path)
if err != nil {
httpErr(w, r, httpFsErr(err), err)
return

View File

@ -68,7 +68,7 @@ func (e *Env) settingsPutHandler(w http.ResponseWriter, r *http.Request) {
settings.Shell = req.Shell
settings.Commands = req.Commands
err = e.Store.Config.SaveSettings(settings)
err = e.Store.SaveSettings(settings)
if err != nil {
httpErr(w, r, http.StatusInternalServerError, err)
return

View File

@ -34,7 +34,7 @@ func (e *Env) shareGetHandler(w http.ResponseWriter, r *http.Request) {
return
}
s, err := e.Store.Share.GetByPath(path)
s, err := e.Store.GetLinksByPath(path)
if err == types.ErrNotExist {
renderJSON(w, r, []*types.ShareLink{})
return
@ -47,7 +47,7 @@ func (e *Env) shareGetHandler(w http.ResponseWriter, r *http.Request) {
for i, link := range s {
if link.Expires && link.ExpireDate.Before(time.Now()) {
e.Store.Share.Delete(link.Hash)
e.Store.DeleteLink(link.Hash)
s = append(s[:i], s[i+1:]...)
}
}
@ -73,7 +73,7 @@ func (e *Env) shareDeleteHandler(w http.ResponseWriter, r *http.Request) {
return
}
err := e.Store.Share.Delete(hash)
err := e.Store.DeleteLink(hash)
if err != nil {
httpErr(w, r, http.StatusInternalServerError, err)
return
@ -92,7 +92,7 @@ func (e *Env) sharePostHandler(w http.ResponseWriter, r *http.Request) {
if expire == "" {
var err error
s, err = e.Store.Share.GetPermanent(path)
s, err = e.Store.GetLinkPermanent(path)
if err == nil {
w.Write([]byte(e.Settings.BaseURL + "/share/" + s.Hash))
return
@ -136,7 +136,7 @@ func (e *Env) sharePostHandler(w http.ResponseWriter, r *http.Request) {
s.ExpireDate = time.Now().Add(add)
}
if err := e.Store.Share.Save(s); err != nil {
if err := e.Store.SaveLink(s); err != nil {
httpErr(w, r, http.StatusInternalServerError, err)
return
}

View File

@ -57,7 +57,7 @@ func (e *Env) usersGetHandler(w http.ResponseWriter, r *http.Request) {
return
}
users, err := e.Store.Users.Gets()
users, err := e.Store.GetUsers()
if err != nil {
httpErr(w, r, http.StatusInternalServerError, err)
return
@ -100,7 +100,7 @@ func (e *Env) userGetHandler(w http.ResponseWriter, r *http.Request) {
return
}
u, err := e.Store.Users.Get(id)
u, err := e.Store.GetUser(id)
if err == types.ErrNotExist {
httpErr(w, r, http.StatusNotFound, nil)
return
@ -121,7 +121,7 @@ func (e *Env) userDeleteHandler(w http.ResponseWriter, r *http.Request) {
return
}
err := e.Store.Users.Delete(id)
err := e.Store.DeleteUser(id)
if err == types.ErrNotExist {
httpErr(w, r, http.StatusNotFound, nil)
return
@ -160,7 +160,7 @@ func (e *Env) userPostHandler(w http.ResponseWriter, r *http.Request) {
return
}
err = e.Store.Users.Save(req.Data)
err = e.Store.SaveUser(req.Data)
if err != nil {
httpErr(w, r, http.StatusInternalServerError, err)
return
@ -198,7 +198,7 @@ func (e *Env) userPutHandler(w http.ResponseWriter, r *http.Request) {
req.Data.Password, err = types.HashPwd(req.Data.Password)
} else {
var suser *types.User
suser, err = e.Store.Users.Get(modifiedID)
suser, err = e.Store.GetUser(modifiedID)
req.Data.Password = suser.Password
}
@ -232,7 +232,7 @@ func (e *Env) userPutHandler(w http.ResponseWriter, r *http.Request) {
req.Which[k] = strings.Title(v)
}
err = e.Store.Users.Update(req.Data, req.Which...)
err = e.Store.UpdateUser(req.Data, req.Which...)
if err != nil {
httpErr(w, r, http.StatusInternalServerError, err)
}

View File

@ -139,10 +139,6 @@ func (e *Env) searchHandler(w http.ResponseWriter, r *http.Request) {
scope := strings.TrimPrefix(r.URL.Path, "/api/search")
err = search.Search(user.Fs, scope, value, func(path string, f os.FileInfo) error {
if !user.IsAllowed(path) {
return nil
}
response, _ := json.Marshal(map[string]interface{}{
"dir": f.IsDir(),
"path": path,

View File

@ -2,8 +2,10 @@ package types
import "net/http"
// Auther is the interface each authentication method must
// implement.
// Auther is the authentication interface.
type Auther interface {
Auth(r *http.Request) (*User, error)
// Auth is called to authenticate a request.
Auth(*http.Request) (*User, error)
// SetStorage gives the Auther the storage.
SetStorage(*Storage)
}

View File

@ -13,4 +13,5 @@ var (
ErrNoPermission = errors.New("permission denied")
ErrInvalidAuthMethod = errors.New("invalid auth method")
ErrEmptyKey = errors.New("empty key")
ErrInvalidDataType = errors.New("invalid data type")
)

View File

@ -35,8 +35,8 @@ type File struct {
Checksums map[string]string `json:"checksums,omitempty"`
}
// NewFileInfo generates a new file info from a user and a path.
func NewFileInfo(u *User, path string) (*File, error) {
// NewFile generates a new file info from a user and a path.
func NewFile(u *User, path string) (*File, error) {
f := &File{
Path: path,
}
@ -120,10 +120,6 @@ func (f *File) getDirInfo() error {
name := i.Name()
path := filepath.Join(f.Path, name)
if !f.user.IsAllowed(path) {
continue
}
if strings.HasPrefix(i.Mode().String(), "L") {
// It's a symbolic link. We try to follow it. If it doesn't work,
// we stay with the link information instead if the target's.

139
types/fs.go Normal file
View File

@ -0,0 +1,139 @@
package types
import (
"os"
"syscall"
"time"
"github.com/spf13/afero"
)
type userFs struct {
source afero.Fs
user *User
settings *Settings
}
func (u *userFs) isAllowed(name string) bool {
if !isAllowed(name, u.user.Rules) {
return false
}
return isAllowed(name, u.settings.Rules)
}
func (u *userFs) Chtimes(name string, a, m time.Time) error {
if !u.isAllowed(name) {
return syscall.ENOENT
}
return u.source.Chtimes(name, a, m)
}
func (u *userFs) Chmod(name string, mode os.FileMode) error {
if !u.isAllowed(name) {
return syscall.ENOENT
}
return u.source.Chmod(name, mode)
}
func (u *userFs) Name() string {
return "userFs"
}
func (u *userFs) Stat(name string) (os.FileInfo, error) {
if !u.isAllowed(name) {
return nil, syscall.ENOENT
}
return u.source.Stat(name)
}
func (u *userFs) Rename(oldname, newname string) error {
if !u.user.Perm.Rename {
return os.ErrPermission
}
if !u.isAllowed(oldname) || !u.isAllowed(newname) {
return syscall.ENOENT
}
return u.source.Rename(oldname, newname)
}
func (u *userFs) RemoveAll(name string) error {
if !u.user.Perm.Delete {
return os.ErrPermission
}
if !u.isAllowed(name) {
return syscall.ENOENT
}
return u.source.RemoveAll(name)
}
func (u *userFs) Remove(name string) error {
if !u.user.Perm.Delete {
return os.ErrPermission
}
if !u.isAllowed(name) {
return syscall.ENOENT
}
return u.source.Remove(name)
}
func (u *userFs) OpenFile(name string, flag int, perm os.FileMode) (afero.File, error) {
if !u.isAllowed(name) {
return nil, syscall.ENOENT
}
return u.source.OpenFile(name, flag, perm)
}
func (u *userFs) Open(name string) (afero.File, error) {
if !u.isAllowed(name) {
return nil, syscall.ENOENT
}
return u.source.Open(name)
}
func (u *userFs) Mkdir(name string, perm os.FileMode) error {
if !u.user.Perm.Create {
return os.ErrPermission
}
if !u.isAllowed(name) {
return syscall.ENOENT
}
return u.source.Mkdir(name, perm)
}
func (u *userFs) MkdirAll(name string, perm os.FileMode) error {
if !u.user.Perm.Create {
return os.ErrPermission
}
if !u.isAllowed(name) {
return syscall.ENOENT
}
return u.source.MkdirAll(name, perm)
}
func (u *userFs) Create(name string) (afero.File, error) {
if !u.user.Perm.Create {
return nil, os.ErrPermission
}
if !u.isAllowed(name) {
return nil, syscall.ENOENT
}
return u.source.Create(name)
}

View File

@ -16,11 +16,6 @@ type Settings struct {
Rules []Rule `json:"rules"` // TODO: use this add to cli
}
// IsAllowed matches the rules against the url.
func (e Settings) IsAllowed(url string) bool {
return isAllowed(url, e.Rules)
}
// Sorting contains a sorting order.
type Sorting struct {
By string `json:"by"`

View File

@ -1,18 +1,222 @@
package types
// Store is used to persist data.
type Store struct {
Users *UsersVerify
Config *ConfigVerify
Share ShareStore
import (
"strings"
)
// StorageBackend is the interface used to persist data.
type StorageBackend interface {
GetUserByID(uint) (*User, error)
GetUserByUsername(string) (*User, error)
GetUsers() ([]*User, error)
SaveUser(u *User) error
UpdateUser(u *User, fields ...string) error
DeleteUserByID(uint) error
DeleteUserByUsername(string) error
GetSettings() (*Settings, error)
SaveSettings(*Settings) error
GetAuther(AuthMethod) (Auther, error)
SaveAuther(Auther) error
GetLinkByHash(hash string) (*ShareLink, error)
GetLinkPermanent(path string) (*ShareLink, error)
GetLinksByPath(path string) ([]*ShareLink, error)
SaveLink(s *ShareLink) error
DeleteLink(hash string) error
}
// ShareStore is the interface to manage share links.
type ShareStore interface {
Get(hash string) (*ShareLink, error)
GetPermanent(path string) (*ShareLink, error)
GetByPath(path string) ([]*ShareLink, error)
Gets() ([]*ShareLink, error)
Save(s *ShareLink) error
Delete(hash string) error
// Storage implements Storage interface and verifies
// the data before getting in and out the database.
type Storage struct {
src StorageBackend
}
// NewStorage creates a Storage from a StorageBackend.
func NewStorage(src StorageBackend) *Storage {
return &Storage{src: src}
}
// GetUser 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 (v *Storage) GetUser(id interface{}) (*User, error) {
var (
user *User
err error
)
switch id.(type) {
case string:
user, err = v.src.GetUserByUsername(id.(string))
case uint:
user, err = v.src.GetUserByID(id.(uint))
default:
return nil, ErrInvalidDataType
}
if err != nil {
return nil, err
}
settings, err := v.GetSettings()
if err != nil {
return nil, err
}
user.clean(settings)
return user, err
}
// GetUsers gets a list of all users.
func (v *Storage) GetUsers() ([]*User, error) {
users, err := v.src.GetUsers()
if err != nil {
return nil, err
}
settings, err := v.GetSettings()
if err != nil {
return nil, err
}
for _, user := range users {
user.clean(settings)
}
return users, err
}
// UpdateUser updates a user in the database.
func (v *Storage) UpdateUser(user *User, fields ...string) error {
settings, err := v.GetSettings()
if err != nil {
return err
}
err = user.clean(settings, fields...)
if err != nil {
return err
}
return v.src.UpdateUser(user, fields...)
}
// SaveUser saves the user in a storage.
func (v *Storage) SaveUser(user *User) error {
settings, err := v.GetSettings()
if err != nil {
return err
}
if err := user.clean(settings); err != nil {
return err
}
return v.src.SaveUser(user)
}
// DeleteUser allows you to delete 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 (v *Storage) DeleteUser(id interface{}) (err error) {
switch id.(type) {
case string:
err = v.src.DeleteUserByUsername(id.(string))
case uint:
err = v.src.DeleteUserByID(id.(uint))
default:
err = ErrInvalidDataType
}
return
}
// GetSettings wraps a ConfigStore.GetSettings
func (v *Storage) GetSettings() (*Settings, error) {
return v.src.GetSettings()
}
// SaveSettings wraps a ConfigStore.SaveSettings
func (v *Storage) SaveSettings(s *Settings) error {
s.BaseURL = strings.TrimSuffix(s.BaseURL, "/")
if len(s.Key) == 0 {
return ErrEmptyKey
}
if s.Defaults.Locale == "" {
s.Defaults.Locale = "en"
}
if s.Defaults.Commands == nil {
s.Defaults.Commands = []string{}
}
if s.Defaults.ViewMode == "" {
s.Defaults.ViewMode = MosaicViewMode
}
if s.Rules == nil {
s.Rules = []Rule{}
}
if s.Shell == nil {
s.Shell = []string{}
}
if s.Commands == nil {
s.Commands = map[string][]string{}
}
for _, event := range defaultEvents {
if _, ok := s.Commands["before_"+event]; !ok {
s.Commands["before_"+event] = []string{}
}
if _, ok := s.Commands["after_"+event]; !ok {
s.Commands["after_"+event] = []string{}
}
}
return v.src.SaveSettings(s)
}
// GetAuther wraps a ConfigStore.GetAuther
func (v *Storage) GetAuther(t AuthMethod) (Auther, error) {
auther, err := v.src.GetAuther(t)
if err != nil {
return nil, err
}
auther.SetStorage(v)
return auther, nil
}
// SaveAuther wraps a ConfigStore.SaveAuther
func (v *Storage) SaveAuther(a Auther) error {
return v.src.SaveAuther(a)
}
// GetLinkByHash wraps a Storage.GetLinkByHash.
func (v *Storage) GetLinkByHash(hash string) (*ShareLink, error) {
return v.src.GetLinkByHash(hash)
}
// GetLinkPermanent wraps a Storage.GetLinkPermanent
func (v *Storage) GetLinkPermanent(path string) (*ShareLink, error) {
return v.src.GetLinkPermanent(path)
}
// GetLinksByPath wraps a Storage.GetLinksByPath
func (v *Storage) GetLinksByPath(path string) ([]*ShareLink, error) {
return v.src.GetLinksByPath(path)
}
// SaveLink wraps a Storage.SaveLink
func (v *Storage) SaveLink(s *ShareLink) error {
return v.src.SaveLink(s)
}
// DeleteLink wraps a Storage.DeleteLink
func (v *Storage) DeleteLink(hash string) error {
return v.src.DeleteLink(hash)
}

View File

@ -1,76 +0,0 @@
package types
import "strings"
// ConfigStore is used to manage configurations relativey to a data storage.
type ConfigStore interface {
GetSettings() (*Settings, error)
SaveSettings(*Settings) error
GetAuther(AuthMethod) (Auther, error)
SaveAuther(Auther) error
}
// ConfigVerify wraps a ConfigStore and makes the verifications needed.
type ConfigVerify struct {
Store ConfigStore
}
// GetSettings wraps a ConfigStore.GetSettings
func (v ConfigVerify) GetSettings() (*Settings, error) {
return v.Store.GetSettings()
}
// SaveSettings wraps a ConfigStore.SaveSettings
func (v ConfigVerify) SaveSettings(s *Settings) error {
s.BaseURL = strings.TrimSuffix(s.BaseURL, "/")
if len(s.Key) == 0 {
return ErrEmptyKey
}
if s.Defaults.Locale == "" {
s.Defaults.Locale = "en"
}
if s.Defaults.Commands == nil {
s.Defaults.Commands = []string{}
}
if s.Defaults.ViewMode == "" {
s.Defaults.ViewMode = MosaicViewMode
}
if s.Rules == nil {
s.Rules = []Rule{}
}
if s.Shell == nil {
s.Shell = []string{}
}
if s.Commands == nil {
s.Commands = map[string][]string{}
}
for _, event := range defaultEvents {
if _, ok := s.Commands["before_"+event]; !ok {
s.Commands["before_"+event] = []string{}
}
if _, ok := s.Commands["after_"+event]; !ok {
s.Commands["after_"+event] = []string{}
}
}
return v.Store.SaveSettings(s)
}
// GetAuther wraps a ConfigStore.GetAuther
func (v ConfigVerify) GetAuther(t AuthMethod) (Auther, error) {
return v.Store.GetAuther(t)
}
// SaveAuther wraps a ConfigStore.SaveAuther
func (v ConfigVerify) SaveAuther(a Auther) error {
return v.Store.SaveAuther(a)
}

View File

@ -1,82 +0,0 @@
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)
}

View File

@ -54,7 +54,7 @@ var checkableFields = []string{
"Rules",
}
func (u *User) clean(fields ...string) error {
func (u *User) clean(settings *Settings, fields ...string) error {
if len(fields) == 0 {
fields = checkableFields
}
@ -93,17 +93,16 @@ func (u *User) clean(fields ...string) error {
}
if u.Fs == nil {
u.Fs = afero.NewBasePathFs(afero.NewOsFs(), u.Scope)
u.Fs = &userFs{
user: u,
settings: settings,
source: afero.NewBasePathFs(afero.NewOsFs(), u.Scope),
}
}
return nil
}
// IsAllowed checks if an user is allowed to go to a certain path.
func (u *User) IsAllowed(url string) bool {
return isAllowed(url, u.Rules)
}
// CanExecute checks if an user can execute a specific command.
func (u *User) CanExecute(command string) bool {
if !u.Perm.Execute {