Read https://github.com/filebrowser/filebrowser/pull/575.

Former-commit-id: 7aedcaaf72b863033e3f089d6df308d41a3fd00c [formerly bdbe4d49161b901c4adf9c245895a1be2d62e4a7] [formerly acfc1ec67c423e0b3e065a8c1f8897c5249af65b [formerly d309066def]]
Former-commit-id: 0c7d925a38a68ccabdf2c4bbd8c302ee89b93509 [formerly a6173925a1382955d93b334ded93f70d6dddd694]
Former-commit-id: e032e0804dd051df86f42962de2b39caec5318b7
This commit is contained in:
Henrique Dias 2019-01-05 22:44:33 +00:00 committed by GitHub
parent 53a4601361
commit 12b2c21522
121 changed files with 5410 additions and 4697 deletions

33
storage/bolt/auth.go Normal file
View file

@ -0,0 +1,33 @@
package bolt
import (
"github.com/asdine/storm"
"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.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)
}

25
storage/bolt/bolt.go Normal file
View file

@ -0,0 +1,25 @@
package bolt
import (
"github.com/filebrowser/filebrowser/v2/settings"
"github.com/asdine/storm"
"github.com/filebrowser/filebrowser/v2/auth"
"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 {
users := users.NewStorage(usersBackend{db: db})
share := share.NewStorage(shareBackend{db: db})
settings := settings.NewStorage(settingsBackend{ db: db})
auth := auth.NewStorage(authBackend{db: db}, users)
return &storage.Storage{
Auth: auth,
Users: users,
Share: share,
Settings: settings,
}
}

19
storage/bolt/config.go Normal file
View file

@ -0,0 +1,19 @@
package bolt
import (
"github.com/asdine/storm"
"github.com/filebrowser/filebrowser/v2/settings"
)
type settingsBackend struct {
db *storm.DB
}
func (s settingsBackend) Get() (*settings.Settings, error) {
settings := &settings.Settings{}
return settings, get(s.db, "settings", settings)
}
func (s settingsBackend) Save(settings *settings.Settings) error {
return save(s.db, "settings", settings)
}

View file

@ -0,0 +1,169 @@
package importer
import (
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
"github.com/filebrowser/filebrowser/v2/auth"
"github.com/filebrowser/filebrowser/v2/users"
"github.com/asdine/storm"
"github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/storage"
"github.com/pelletier/go-toml"
"gopkg.in/yaml.v2"
)
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"`
}
type oldConf struct {
Port int `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 importConf(db *storm.DB, path string, sto *storage.Storage) error {
cfg := &oldConf{}
if path != "" {
ext := filepath.Ext(path)
fd, err := os.Open(path)
if err != nil {
return 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 errors.New("unsupported config extension " + ext)
}
if err != nil {
return err
}
} else {
cfg = defaults
path, err := filepath.Abs(".")
if err != nil {
return err
}
cfg.Defaults.Scope = path
}
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,
BaseURL: cfg.BaseURL,
Log: cfg.Log,
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{
Address: cfg.Address,
Port: cfg.Port,
},
}
var auther auth.Auther
switch cfg.Auth.Method {
case "proxy":
auther = &auth.ProxyAuth{Header: cfg.Auth.Header}
s.AuthMethod = auth.MethodProxyAuth
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
}
fmt.Println("Configuration successfully imported.")
return nil
}

View file

@ -0,0 +1,35 @@
package importer
import (
"github.com/asdine/storm"
"github.com/filebrowser/filebrowser/v2/storage/bolt"
)
// Import imports an old configuration to a newer database.
func Import(oldDB, oldConf, newDB string) error {
old, err := storm.Open(oldDB)
if err != nil {
return err
}
defer old.Close()
new, err := storm.Open(newDB)
if err != nil {
return err
}
defer new.Close()
sto := bolt.NewStorage(new)
err = importUsers(old, sto)
if err != nil {
return err
}
err = importConf(old, oldConf, sto)
if err != nil {
return err
}
return err
}

View file

@ -0,0 +1,121 @@
package importer
import (
"encoding/json"
"fmt"
"path/filepath"
"github.com/asdine/storm"
"github.com/filebrowser/filebrowser/v2/rules"
"github.com/filebrowser/filebrowser/v2/storage"
"github.com/filebrowser/filebrowser/v2/users"
"go.etcd.io/bbolt"
)
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) {
users := []*oldUser{}
err := db.Bolt.View(func(tx *bolt.Tx) error {
return tx.Bucket([]byte("User")).ForEach(func(k []byte, v []byte) error {
if len(v) > 0 && string(v)[0] == '{' {
user := &oldUser{}
err := json.Unmarshal(v, user)
if err != nil {
return err
}
users = append(users, user)
}
return nil
})
})
return users, err
}
func convertUsersToNew(old []*oldUser) ([]*users.User, error) {
var err error
list := []*users.User{}
for _, oldUser := range old {
user := &users.User{
ID: uint(oldUser.ID),
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)
}
user.Scope, err = filepath.Abs(user.Scope)
if err != nil {
return nil, err
}
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
}

50
storage/bolt/share.go Normal file
View file

@ -0,0 +1,50 @@
package bolt
import (
"github.com/asdine/storm"
"github.com/asdine/storm/q"
"github.com/filebrowser/filebrowser/v2/errors"
"github.com/filebrowser/filebrowser/v2/share"
)
type shareBackend struct {
db *storm.DB
}
func (s shareBackend) GetByHash(hash string) (*share.Link, error) {
var v share.Link
err := s.db.One("Hash", hash, &v)
if err == storm.ErrNotFound {
return nil, errors.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 err == storm.ErrNotFound {
return nil, errors.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 err == storm.ErrNotFound {
return v, errors.ErrNotExist
}
return v, err
}
func (s shareBackend) Save(l *share.Link) error {
return s.db.Save(l)
}
func (s shareBackend) Delete(hash string) error {
return s.db.DeleteStruct(&share.Link{Hash: hash})
}

91
storage/bolt/users.go Normal file
View file

@ -0,0 +1,91 @@
package bolt
import (
"reflect"
"github.com/asdine/storm"
"github.com/filebrowser/filebrowser/v2/errors"
"github.com/filebrowser/filebrowser/v2/users"
)
type usersBackend struct {
db *storm.DB
}
func (st usersBackend) GetByID(id uint) (*users.User, error) {
user := &users.User{}
err := st.db.One("ID", id, user)
if err == storm.ErrNotFound {
return nil, errors.ErrNotExist
}
if err != nil {
return nil, err
}
return user, nil
}
func (st usersBackend) GetByUsername(username string) (*users.User, error) {
user := &users.User{}
err := st.db.One("Username", username, user)
if err == storm.ErrNotFound {
return nil, errors.ErrNotExist
}
if err != nil {
return nil, err
}
return user, nil
}
func (st usersBackend) Gets() ([]*users.User, error) {
users := []*users.User{}
err := st.db.All(&users)
if err == storm.ErrNotFound {
return nil, errors.ErrNotExist
}
if err != nil {
return users, err
}
return users, err
}
func (st usersBackend) Update(user *users.User, fields ...string) error {
if len(fields) == 0 {
return st.Save(user)
}
for _, field := range fields {
val := reflect.ValueOf(user).Elem().FieldByName(field).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 err == storm.ErrAlreadyExists {
return errors.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.GetByUsername(username)
if err != nil {
return err
}
return st.db.DeleteStruct(user)
}

19
storage/bolt/utils.go Normal file
View file

@ -0,0 +1,19 @@
package bolt
import (
"github.com/asdine/storm"
"github.com/filebrowser/filebrowser/v2/errors"
)
func get(db *storm.DB, name string, to interface{}) error {
err := db.Get("config", name, to)
if err == storm.ErrNotFound {
return errors.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
View 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 whih makes the neccessary
// verifications when fetching and saving data to ensure consistency.
type Storage struct {
Users *users.Storage
Share *share.Storage
Auth *auth.Storage
Settings *settings.Storage
}