feat: filebrowser with encfs
This commit is contained in:
36
storage/bolt/auth.go
Normal file
36
storage/bolt/auth.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package bolt
|
||||
|
||||
import (
|
||||
"github.com/asdine/storm/v3"
|
||||
|
||||
"github.com/filebrowser/filebrowser/v2/auth"
|
||||
"github.com/filebrowser/filebrowser/v2/errors"
|
||||
"github.com/filebrowser/filebrowser/v2/settings"
|
||||
)
|
||||
|
||||
type authBackend struct {
|
||||
db *storm.DB
|
||||
}
|
||||
|
||||
func (s authBackend) Get(t settings.AuthMethod) (auth.Auther, error) {
|
||||
var auther auth.Auther
|
||||
|
||||
switch t {
|
||||
case auth.MethodJSONAuth:
|
||||
auther = &auth.JSONAuth{}
|
||||
case auth.MethodProxyAuth:
|
||||
auther = &auth.ProxyAuth{}
|
||||
case auth.MethodHookAuth:
|
||||
auther = &auth.HookAuth{}
|
||||
case auth.MethodNoAuth:
|
||||
auther = &auth.NoAuth{}
|
||||
default:
|
||||
return nil, errors.ErrInvalidAuthMethod
|
||||
}
|
||||
|
||||
return auther, get(s.db, "auther", auther)
|
||||
}
|
||||
|
||||
func (s authBackend) Save(a auth.Auther) error {
|
||||
return save(s.db, "auther", a)
|
||||
}
|
||||
31
storage/bolt/bolt.go
Normal file
31
storage/bolt/bolt.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package bolt
|
||||
|
||||
import (
|
||||
"github.com/asdine/storm/v3"
|
||||
|
||||
"github.com/filebrowser/filebrowser/v2/auth"
|
||||
"github.com/filebrowser/filebrowser/v2/settings"
|
||||
"github.com/filebrowser/filebrowser/v2/share"
|
||||
"github.com/filebrowser/filebrowser/v2/storage"
|
||||
"github.com/filebrowser/filebrowser/v2/users"
|
||||
)
|
||||
|
||||
// NewStorage creates a storage.Storage based on Bolt DB.
|
||||
func NewStorage(db *storm.DB) (*storage.Storage, error) {
|
||||
userStore := users.NewStorage(usersBackend{db: db})
|
||||
shareStore := share.NewStorage(shareBackend{db: db})
|
||||
settingsStore := settings.NewStorage(settingsBackend{db: db})
|
||||
authStore := auth.NewStorage(authBackend{db: db}, userStore)
|
||||
|
||||
err := save(db, "version", 2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &storage.Storage{
|
||||
Auth: authStore,
|
||||
Users: userStore,
|
||||
Share: shareStore,
|
||||
Settings: settingsStore,
|
||||
}, nil
|
||||
}
|
||||
29
storage/bolt/config.go
Normal file
29
storage/bolt/config.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package bolt
|
||||
|
||||
import (
|
||||
"github.com/asdine/storm/v3"
|
||||
|
||||
"github.com/filebrowser/filebrowser/v2/settings"
|
||||
)
|
||||
|
||||
type settingsBackend struct {
|
||||
db *storm.DB
|
||||
}
|
||||
|
||||
func (s settingsBackend) Get() (*settings.Settings, error) {
|
||||
set := &settings.Settings{}
|
||||
return set, get(s.db, "settings", set)
|
||||
}
|
||||
|
||||
func (s settingsBackend) Save(set *settings.Settings) error {
|
||||
return save(s.db, "settings", set)
|
||||
}
|
||||
|
||||
func (s settingsBackend) GetServer() (*settings.Server, error) {
|
||||
server := &settings.Server{}
|
||||
return server, get(s.db, "server", server)
|
||||
}
|
||||
|
||||
func (s settingsBackend) SaveServer(server *settings.Server) error {
|
||||
return save(s.db, "server", server)
|
||||
}
|
||||
187
storage/bolt/importer/conf.go
Normal file
187
storage/bolt/importer/conf.go
Normal file
@@ -0,0 +1,187 @@
|
||||
package importer
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/asdine/storm/v3"
|
||||
"github.com/pelletier/go-toml/v2"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/filebrowser/filebrowser/v2/auth"
|
||||
"github.com/filebrowser/filebrowser/v2/settings"
|
||||
"github.com/filebrowser/filebrowser/v2/storage"
|
||||
"github.com/filebrowser/filebrowser/v2/users"
|
||||
)
|
||||
|
||||
type oldDefs struct {
|
||||
Commands []string `json:"commands" yaml:"commands" toml:"commands"`
|
||||
Scope string `json:"scope" yaml:"scope" toml:"scope"`
|
||||
ViewMode string `json:"viewMode" yaml:"viewMode" toml:"viewMode"`
|
||||
Locale string `json:"locale" yaml:"locale" toml:"locale"`
|
||||
AllowCommands bool `json:"allowCommands" yaml:"allowCommands" toml:"allowCommands"`
|
||||
AllowEdit bool `json:"allowEdit" yaml:"allowEdit" toml:"allowEdit"`
|
||||
AllowNew bool `json:"allowNew" yaml:"allowNew" toml:"allowNew"`
|
||||
}
|
||||
|
||||
type oldAuth struct {
|
||||
Method string `json:"method" yaml:"method" toml:"method"` // default none proxy
|
||||
Header string `json:"header" yaml:"header" toml:"header"`
|
||||
Command string `json:"command" yaml:"command" toml:"command"`
|
||||
}
|
||||
|
||||
type oldConf struct {
|
||||
Port string `json:"port" yaml:"port" toml:"port"`
|
||||
BaseURL string `json:"baseURL" yaml:"baseURL" toml:"baseURL"`
|
||||
Log string `json:"log" yaml:"log" toml:"log"`
|
||||
Address string `json:"address" yaml:"address" toml:"address"`
|
||||
Defaults oldDefs `json:"defaults" yaml:"defaults" toml:"defaults"`
|
||||
ReCaptcha struct {
|
||||
Key string `json:"key" yaml:"key" toml:"key"`
|
||||
Secret string `json:"secret" yaml:"secret" toml:"secret"`
|
||||
Host string `json:"host" yaml:"host" toml:"host"`
|
||||
} `json:"recaptcha" yaml:"recaptcha" toml:"recaptcha"`
|
||||
Auth oldAuth `json:"auth" yaml:"auth" toml:"auth"`
|
||||
}
|
||||
|
||||
var defaults = &oldConf{
|
||||
Port: "0",
|
||||
Log: "stdout",
|
||||
Defaults: oldDefs{
|
||||
Commands: []string{"git", "svn", "hg"},
|
||||
ViewMode: string(users.MosaicViewMode),
|
||||
AllowCommands: true,
|
||||
AllowEdit: true,
|
||||
AllowNew: true,
|
||||
Locale: "en",
|
||||
},
|
||||
Auth: oldAuth{
|
||||
Method: "default",
|
||||
},
|
||||
}
|
||||
|
||||
func readConf(path string) (*oldConf, error) {
|
||||
cfg := &oldConf{}
|
||||
if path != "" {
|
||||
ext := filepath.Ext(path)
|
||||
|
||||
fd, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
switch ext {
|
||||
case ".json":
|
||||
err = json.NewDecoder(fd).Decode(cfg)
|
||||
case ".toml":
|
||||
err = toml.NewDecoder(fd).Decode(cfg)
|
||||
case ".yaml", ".yml":
|
||||
err = yaml.NewDecoder(fd).Decode(cfg)
|
||||
default:
|
||||
return nil, errors.New("unsupported config extension " + ext)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
cfg = defaults
|
||||
path, err := filepath.Abs(".")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfg.Defaults.Scope = path
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func importConf(db *storm.DB, path string, sto *storage.Storage) error {
|
||||
cfg, err := readConf(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
commands := map[string][]string{}
|
||||
err = db.Get("config", "commands", &commands)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
key := []byte{}
|
||||
err = db.Get("config", "key", &key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s := &settings.Settings{
|
||||
Key: key,
|
||||
Signup: false,
|
||||
Defaults: settings.UserDefaults{
|
||||
Scope: cfg.Defaults.Scope,
|
||||
Commands: cfg.Defaults.Commands,
|
||||
ViewMode: users.ViewMode(cfg.Defaults.ViewMode),
|
||||
Locale: cfg.Defaults.Locale,
|
||||
Perm: users.Permissions{
|
||||
Admin: false,
|
||||
Execute: cfg.Defaults.AllowCommands,
|
||||
Create: cfg.Defaults.AllowNew,
|
||||
Rename: cfg.Defaults.AllowEdit,
|
||||
Modify: cfg.Defaults.AllowEdit,
|
||||
Delete: cfg.Defaults.AllowEdit,
|
||||
Share: true,
|
||||
Download: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
server := &settings.Server{
|
||||
BaseURL: cfg.BaseURL,
|
||||
Port: cfg.Port,
|
||||
Address: cfg.Address,
|
||||
Log: cfg.Log,
|
||||
}
|
||||
|
||||
var auther auth.Auther
|
||||
switch cfg.Auth.Method {
|
||||
case "proxy":
|
||||
auther = &auth.ProxyAuth{Header: cfg.Auth.Header}
|
||||
s.AuthMethod = auth.MethodProxyAuth
|
||||
case "hook":
|
||||
auther = &auth.HookAuth{Command: cfg.Auth.Command}
|
||||
s.AuthMethod = auth.MethodHookAuth
|
||||
case "none":
|
||||
auther = &auth.NoAuth{}
|
||||
s.AuthMethod = auth.MethodNoAuth
|
||||
default:
|
||||
auther = &auth.JSONAuth{
|
||||
ReCaptcha: &auth.ReCaptcha{
|
||||
Host: cfg.ReCaptcha.Host,
|
||||
Key: cfg.ReCaptcha.Key,
|
||||
Secret: cfg.ReCaptcha.Secret,
|
||||
},
|
||||
}
|
||||
s.AuthMethod = auth.MethodJSONAuth
|
||||
}
|
||||
|
||||
err = sto.Auth.Save(auther)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = sto.Settings.Save(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = sto.Settings.SaveServer(server)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("Configuration successfully imported.")
|
||||
return nil
|
||||
}
|
||||
39
storage/bolt/importer/importer.go
Normal file
39
storage/bolt/importer/importer.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package importer
|
||||
|
||||
import (
|
||||
"github.com/asdine/storm/v3"
|
||||
|
||||
"github.com/filebrowser/filebrowser/v2/storage/bolt"
|
||||
)
|
||||
|
||||
// Import imports an old configuration to a newer database.
|
||||
func Import(oldDBPath, oldConf, newDBPath string) error {
|
||||
oldDB, err := storm.Open(oldDBPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer oldDB.Close()
|
||||
|
||||
newDB, err := storm.Open(newDBPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer newDB.Close()
|
||||
|
||||
sto, err := bolt.NewStorage(newDB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = importUsers(oldDB, sto)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = importConf(oldDB, oldConf, sto)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
114
storage/bolt/importer/users.go
Normal file
114
storage/bolt/importer/users.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package importer
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/asdine/storm/v3"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
|
||||
"github.com/filebrowser/filebrowser/v2/rules"
|
||||
"github.com/filebrowser/filebrowser/v2/storage"
|
||||
"github.com/filebrowser/filebrowser/v2/users"
|
||||
)
|
||||
|
||||
type oldUser struct {
|
||||
ID int `storm:"id,increment"`
|
||||
Admin bool `json:"admin"`
|
||||
AllowCommands bool `json:"allowCommands"` // Execute commands
|
||||
AllowEdit bool `json:"allowEdit"` // Edit/rename files
|
||||
AllowNew bool `json:"allowNew"` // Create files and folders
|
||||
AllowPublish bool `json:"allowPublish"` // Publish content (to use with static gen)
|
||||
LockPassword bool `json:"lockPassword"`
|
||||
Commands []string `json:"commands"`
|
||||
Locale string `json:"locale"`
|
||||
Password string `json:"password"`
|
||||
Rules []*rules.Rule `json:"rules"`
|
||||
Scope string `json:"filesystem"`
|
||||
Username string `json:"username" storm:"index,unique"`
|
||||
ViewMode string `json:"viewMode"`
|
||||
}
|
||||
|
||||
func readOldUsers(db *storm.DB) ([]*oldUser, error) {
|
||||
var oldUsers []*oldUser
|
||||
err := db.Bolt.View(func(tx *bolt.Tx) error {
|
||||
return tx.Bucket([]byte("User")).ForEach(func(_ []byte, v []byte) error {
|
||||
if len(v) > 0 && string(v)[0] == '{' {
|
||||
user := &oldUser{}
|
||||
err := json.Unmarshal(v, user)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
oldUsers = append(oldUsers, user)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
})
|
||||
|
||||
return oldUsers, err
|
||||
}
|
||||
|
||||
func convertUsersToNew(old []*oldUser) ([]*users.User, error) {
|
||||
list := []*users.User{}
|
||||
|
||||
for _, oldUser := range old {
|
||||
user := &users.User{
|
||||
Username: oldUser.Username,
|
||||
Password: oldUser.Password,
|
||||
Scope: oldUser.Scope,
|
||||
Locale: oldUser.Locale,
|
||||
LockPassword: oldUser.LockPassword,
|
||||
ViewMode: users.ViewMode(oldUser.ViewMode),
|
||||
Commands: oldUser.Commands,
|
||||
Rules: []rules.Rule{},
|
||||
Perm: users.Permissions{
|
||||
Admin: oldUser.Admin,
|
||||
Execute: oldUser.AllowCommands,
|
||||
Create: oldUser.AllowNew,
|
||||
Rename: oldUser.AllowEdit,
|
||||
Modify: oldUser.AllowEdit,
|
||||
Delete: oldUser.AllowEdit,
|
||||
Share: true,
|
||||
Download: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rule := range oldUser.Rules {
|
||||
user.Rules = append(user.Rules, *rule)
|
||||
}
|
||||
|
||||
err := user.Clean("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
list = append(list, user)
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func importUsers(old *storm.DB, sto *storage.Storage) error {
|
||||
oldUsers, err := readOldUsers(old)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newUsers, err := convertUsersToNew(oldUsers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, user := range newUsers {
|
||||
err = sto.Users.Save(user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("%d users successfully imported into the new DB.\n", len(newUsers))
|
||||
return nil
|
||||
}
|
||||
77
storage/bolt/share.go
Normal file
77
storage/bolt/share.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package bolt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/asdine/storm/v3"
|
||||
"github.com/asdine/storm/v3/q"
|
||||
|
||||
fbErrors "github.com/filebrowser/filebrowser/v2/errors"
|
||||
"github.com/filebrowser/filebrowser/v2/share"
|
||||
)
|
||||
|
||||
type shareBackend struct {
|
||||
db *storm.DB
|
||||
}
|
||||
|
||||
func (s shareBackend) All() ([]*share.Link, error) {
|
||||
var v []*share.Link
|
||||
err := s.db.All(&v)
|
||||
if errors.Is(err, storm.ErrNotFound) {
|
||||
return v, fbErrors.ErrNotExist
|
||||
}
|
||||
|
||||
return v, err
|
||||
}
|
||||
|
||||
func (s shareBackend) FindByUserID(id uint) ([]*share.Link, error) {
|
||||
var v []*share.Link
|
||||
err := s.db.Select(q.Eq("UserID", id)).Find(&v)
|
||||
if errors.Is(err, storm.ErrNotFound) {
|
||||
return v, fbErrors.ErrNotExist
|
||||
}
|
||||
|
||||
return v, err
|
||||
}
|
||||
|
||||
func (s shareBackend) GetByHash(hash string) (*share.Link, error) {
|
||||
var v share.Link
|
||||
err := s.db.One("Hash", hash, &v)
|
||||
if errors.Is(err, storm.ErrNotFound) {
|
||||
return nil, fbErrors.ErrNotExist
|
||||
}
|
||||
|
||||
return &v, err
|
||||
}
|
||||
|
||||
func (s shareBackend) GetPermanent(path string, id uint) (*share.Link, error) {
|
||||
var v share.Link
|
||||
err := s.db.Select(q.Eq("Path", path), q.Eq("Expire", 0), q.Eq("UserID", id)).First(&v)
|
||||
if errors.Is(err, storm.ErrNotFound) {
|
||||
return nil, fbErrors.ErrNotExist
|
||||
}
|
||||
|
||||
return &v, err
|
||||
}
|
||||
|
||||
func (s shareBackend) Gets(path string, id uint) ([]*share.Link, error) {
|
||||
var v []*share.Link
|
||||
err := s.db.Select(q.Eq("Path", path), q.Eq("UserID", id)).Find(&v)
|
||||
if errors.Is(err, storm.ErrNotFound) {
|
||||
return v, fbErrors.ErrNotExist
|
||||
}
|
||||
|
||||
return v, err
|
||||
}
|
||||
|
||||
func (s shareBackend) Save(l *share.Link) error {
|
||||
return s.db.Save(l)
|
||||
}
|
||||
|
||||
func (s shareBackend) Delete(hash string) error {
|
||||
err := s.db.DeleteStruct(&share.Link{Hash: hash})
|
||||
if errors.Is(err, storm.ErrNotFound) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
95
storage/bolt/users.go
Normal file
95
storage/bolt/users.go
Normal file
@@ -0,0 +1,95 @@
|
||||
package bolt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/asdine/storm/v3"
|
||||
|
||||
fbErrors "github.com/filebrowser/filebrowser/v2/errors"
|
||||
"github.com/filebrowser/filebrowser/v2/users"
|
||||
)
|
||||
|
||||
type usersBackend struct {
|
||||
db *storm.DB
|
||||
}
|
||||
|
||||
func (st usersBackend) GetBy(i interface{}) (user *users.User, err error) {
|
||||
user = &users.User{}
|
||||
|
||||
var arg string
|
||||
switch i.(type) {
|
||||
case uint:
|
||||
arg = "ID"
|
||||
case string:
|
||||
arg = "Username"
|
||||
default:
|
||||
return nil, fbErrors.ErrInvalidDataType
|
||||
}
|
||||
|
||||
err = st.db.One(arg, i, user)
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, storm.ErrNotFound) {
|
||||
return nil, fbErrors.ErrNotExist
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (st usersBackend) Gets() ([]*users.User, error) {
|
||||
var allUsers []*users.User
|
||||
err := st.db.All(&allUsers)
|
||||
if errors.Is(err, storm.ErrNotFound) {
|
||||
return nil, fbErrors.ErrNotExist
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return allUsers, err
|
||||
}
|
||||
|
||||
return allUsers, err
|
||||
}
|
||||
|
||||
func (st usersBackend) Update(user *users.User, fields ...string) error {
|
||||
if len(fields) == 0 {
|
||||
return st.Save(user)
|
||||
}
|
||||
|
||||
for _, field := range fields {
|
||||
userField := reflect.ValueOf(user).Elem().FieldByName(field)
|
||||
if !userField.IsValid() {
|
||||
return fmt.Errorf("invalid field: %s", field)
|
||||
}
|
||||
val := userField.Interface()
|
||||
if err := st.db.UpdateField(user, field, val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st usersBackend) Save(user *users.User) error {
|
||||
err := st.db.Save(user)
|
||||
if errors.Is(err, storm.ErrAlreadyExists) {
|
||||
return fbErrors.ErrExist
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (st usersBackend) DeleteByID(id uint) error {
|
||||
return st.db.DeleteStruct(&users.User{ID: id})
|
||||
}
|
||||
|
||||
func (st usersBackend) DeleteByUsername(username string) error {
|
||||
user, err := st.GetBy(username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return st.db.DeleteStruct(user)
|
||||
}
|
||||
22
storage/bolt/utils.go
Normal file
22
storage/bolt/utils.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package bolt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/asdine/storm/v3"
|
||||
|
||||
fbErrors "github.com/filebrowser/filebrowser/v2/errors"
|
||||
)
|
||||
|
||||
func get(db *storm.DB, name string, to interface{}) error {
|
||||
err := db.Get("config", name, to)
|
||||
if errors.Is(err, storm.ErrNotFound) {
|
||||
return fbErrors.ErrNotExist
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func save(db *storm.DB, name string, from interface{}) error {
|
||||
return db.Set("config", name, from)
|
||||
}
|
||||
17
storage/storage.go
Normal file
17
storage/storage.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"github.com/filebrowser/filebrowser/v2/auth"
|
||||
"github.com/filebrowser/filebrowser/v2/settings"
|
||||
"github.com/filebrowser/filebrowser/v2/share"
|
||||
"github.com/filebrowser/filebrowser/v2/users"
|
||||
)
|
||||
|
||||
// Storage is a storage powered by a Backend which makes the necessary
|
||||
// verifications when fetching and saving data to ensure consistency.
|
||||
type Storage struct {
|
||||
Users users.Store
|
||||
Share *share.Storage
|
||||
Auth *auth.Storage
|
||||
Settings *settings.Storage
|
||||
}
|
||||
Reference in New Issue
Block a user