feat: import command

License: MIT
Signed-off-by: Henrique Dias <hacdias@gmail.com>
This commit is contained in:
Henrique Dias 2019-01-05 12:15:47 +00:00
parent f08dc33b62
commit 311321eedf
13 changed files with 465 additions and 43 deletions

View File

@ -9,8 +9,8 @@ import (
"text/tabwriter"
"github.com/filebrowser/filebrowser/auth"
"github.com/filebrowser/filebrowser/settings"
"github.com/filebrowser/filebrowser/errors"
"github.com/filebrowser/filebrowser/settings"
"github.com/spf13/cobra"
)
@ -35,6 +35,12 @@ func addConfigFlags(cmd *cobra.Command) {
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().StringP("address", "a", "127.0.0.1", "default address to listen to")
cmd.Flags().StringP("log", "l", "stderr", "log output")
cmd.Flags().IntP("port", "p", 0, "default port to listen to")
cmd.Flags().String("tls.cert", "", "tls certificate path")
cmd.Flags().String("tls.key", "", "tls key path")
cmd.Flags().String("auth.method", string(auth.MethodJSONAuth), "authentication type")
cmd.Flags().String("auth.header", "", "HTTP header for auth.method=proxy")
@ -94,7 +100,13 @@ func printSettings(s *settings.Settings, auther auth.Auther) {
fmt.Fprintf(w, "\nBase URL:\t%s\n", s.BaseURL)
fmt.Fprintf(w, "Sign up:\t%t\n", s.Signup)
fmt.Fprintf(w, "Auth method:\t%s\n", s.AuthMethod)
fmt.Fprintf(w, "Shell:\t%s\t", 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.Fprintln(w, "\nServer:")
fmt.Fprintf(w, "\tAddress:\t%s\n", s.Server.Address)
fmt.Fprintf(w, "\tPort:\t%d\n", s.Server.Port)
fmt.Fprintf(w, "\tTLS Cert:\t%s\n", s.Server.TLSCert)
fmt.Fprintf(w, "\tTLS Key:\t%s\n", s.Server.TLSKey)
fmt.Fprintln(w, "\nBranding:")
fmt.Fprintf(w, "\tName:\t%s\n", s.Branding.Name)
fmt.Fprintf(w, "\tFiles override:\t%s\n", s.Branding.Files)

View File

@ -43,15 +43,22 @@ override the options.`,
s := &settings.Settings{
Key: generateRandomBytes(64), // 256 bit
BaseURL: mustGetString(cmd, "baseURL"),
Log: mustGetString(cmd, "log"),
Signup: mustGetBool(cmd, "signup"),
Shell: strings.Split(strings.TrimSpace(mustGetString(cmd, "shell")), " "),
AuthMethod: authMethod,
Defaults: defaults,
Server: settings.Server{
Address: mustGetString(cmd, "address"),
Port: mustGetInt(cmd, "port"),
TLSCert: mustGetString(cmd, "tls.cert"),
TLSKey: mustGetString(cmd, "tls.key"),
},
Branding: settings.Branding{
Name: mustGetString(cmd, "branding.name"),
DisableExternal: mustGetBool(cmd, "branding.disableExternal"),
Files: mustGetString(cmd, "branding.files"),
},
Defaults: defaults,
}
err = st.Settings.Save(s)

View File

@ -31,19 +31,29 @@ you want to change.`,
cmd.Flags().Visit(func(flag *pflag.Flag) {
switch flag.Name {
case "baseURL":
s.BaseURL = mustGetString(cmd, "baseURL")
s.BaseURL = mustGetString(cmd, flag.Name)
case "signup":
s.Signup = mustGetBool(cmd, "signup")
s.Signup = mustGetBool(cmd, flag.Name)
case "auth.method":
hasAuth = true
case "shell":
s.Shell = strings.Split(strings.TrimSpace(mustGetString(cmd, "shell")), " ")
s.Shell = strings.Split(strings.TrimSpace(mustGetString(cmd, flag.Name)), " ")
case "branding.name":
s.Branding.Name = mustGetString(cmd, "branding.name")
s.Branding.Name = mustGetString(cmd, flag.Name)
case "branding.disableExternal":
s.Branding.DisableExternal = mustGetBool(cmd, "branding.disableExternal")
s.Branding.DisableExternal = mustGetBool(cmd, flag.Name)
case "branding.files":
s.Branding.Files = mustGetString(cmd, "branding.files")
s.Branding.Files = mustGetString(cmd, flag.Name)
case "log":
s.Log = mustGetString(cmd, flag.Name)
case "address":
s.Server.Address = mustGetString(cmd, flag.Name)
case "port":
s.Server.Port = mustGetInt(cmd, flag.Name)
case "tls.cert":
s.Server.TLSCert = mustGetString(cmd, flag.Name)
case "tls.key":
s.Server.TLSKey = mustGetString(cmd, flag.Name)
}
})

27
cmd/import.go Normal file
View File

@ -0,0 +1,27 @@
package cmd
import (
"github.com/filebrowser/filebrowser/storage/bolt/importer"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(importCmd)
importCmd.Flags().String("old.db", "", "")
importCmd.Flags().String("old.config", "", "")
}
var importCmd = &cobra.Command{
Use: "import",
Short: "Imports an old configuration.",
Long: `Imports an old configuration`,
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
oldDB := mustGetString(cmd, "old.db")
oldConf := mustGetString(cmd, "old.config")
err := importer.Import(oldDB, oldConf, databasePath)
checkErr(err)
},
}

View File

@ -14,10 +14,12 @@ import (
"github.com/asdine/storm"
"github.com/filebrowser/filebrowser/auth"
"github.com/filebrowser/filebrowser/settings"
"github.com/filebrowser/filebrowser/storage"
"github.com/filebrowser/filebrowser/users"
fbhttp "github.com/filebrowser/filebrowser/http"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
lumberjack "gopkg.in/natefinch/lumberjack.v2"
)
@ -28,11 +30,11 @@ var (
func init() {
rootCmd.PersistentFlags().StringVarP(&databasePath, "database", "d", "./filebrowser.db", "path to the database")
rootCmd.Flags().StringP("address", "a", "127.0.0.1", "address to listen on")
rootCmd.Flags().StringP("log", "l", "stderr", "log output")
rootCmd.Flags().IntP("port", "p", 0, "port to listen on")
rootCmd.Flags().StringP("cert", "c", "", "tls certificate")
rootCmd.Flags().StringP("key", "k", "", "tls key")
rootCmd.Flags().StringP("address", "a", "", "address to listen on (default comes from database)")
rootCmd.Flags().StringP("log", "l", "", "log output (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("key", "k", "", "tls key (default comes from database)")
rootCmd.Flags().StringP("scope", "s", "", "scope for users")
}
@ -46,29 +48,27 @@ web interface.
If you've never run File Browser, you will need to create the database.
See 'filebrowser help config init' for more information.
This command is used to start up the server. By default it starts
listening on loalhost on a random port. Use the flags to change it.`,
Run: func(cmd *cobra.Command, args []string) {
setupLogger(cmd)
This command is used to start up the server. By default it starts listening
on localhost on a random port unless specified otherwise in the database or
via flags.
Use the available flags to override the database/default options. These flags
values won't be persisted to the database. To persist configuration to the database
use the command 'filebrowser config set'.`,
Run: func(cmd *cobra.Command, args []string) {
if _, err := os.Stat(databasePath); os.IsNotExist(err) {
quickSetup(cmd)
}
var err error
db := getDB()
defer db.Close()
st := getStorage(db)
handler, err := fbhttp.NewHandler(st)
checkErr(err)
startServer(cmd, handler)
startServer(cmd, st)
},
}
func setupLogger(cmd *cobra.Command) {
switch l := mustGetString(cmd, "log"); l {
func setupLogger(s *settings.Settings) {
switch s.Log {
case "stdout":
log.SetOutput(os.Stdout)
case "stderr":
@ -77,7 +77,7 @@ func setupLogger(cmd *cobra.Command) {
log.SetOutput(ioutil.Discard)
default:
log.SetOutput(&lumberjack.Logger{
Filename: l,
Filename: s.Log,
MaxSize: 100,
MaxAge: 14,
MaxBackups: 10,
@ -85,6 +85,23 @@ func setupLogger(cmd *cobra.Command) {
}
}
func serverVisitAndReplace(cmd *cobra.Command, s *settings.Settings) {
cmd.Flags().Visit(func(flag *pflag.Flag) {
switch flag.Name {
case "log":
s.Log = mustGetString(cmd, flag.Name)
case "address":
s.Server.Address = mustGetString(cmd, flag.Name)
case "port":
s.Server.Port = mustGetInt(cmd, flag.Name)
case "cert":
s.Server.TLSCert = mustGetString(cmd, flag.Name)
case "key":
s.Server.TLSKey = mustGetString(cmd, flag.Name)
}
})
}
func quickSetup(cmd *cobra.Command) {
scope := mustGetString(cmd, "scope")
if scope == "" {
@ -98,8 +115,15 @@ func quickSetup(cmd *cobra.Command) {
set := &settings.Settings{
Key: generateRandomBytes(64), // 256 bit
BaseURL: "",
Log: "stderr",
Signup: false,
AuthMethod: auth.MethodJSONAuth,
Server: settings.Server{
Port: 0,
Address: "127.0.0.1",
TLSCert: mustGetString(cmd, "cert"),
TLSKey: mustGetString(cmd, "key"),
},
Defaults: settings.UserDefaults{
Scope: scope,
Locale: "en",
@ -116,6 +140,7 @@ func quickSetup(cmd *cobra.Command) {
},
}
serverVisitAndReplace(cmd, set)
st := getStorage(db)
err = st.Settings.Save(set)
@ -140,24 +165,26 @@ func quickSetup(cmd *cobra.Command) {
checkErr(err)
}
func startServer(cmd *cobra.Command, handler http.Handler) {
addr := mustGetString(cmd, "address")
port, err := cmd.Flags().GetInt("port")
func startServer(cmd *cobra.Command, st *storage.Storage) {
settings, err := st.Settings.Get()
checkErr(err)
cert := mustGetString(cmd, "cert")
key := mustGetString(cmd, "key")
serverVisitAndReplace(cmd, settings)
setupLogger(settings)
handler, err := fbhttp.NewHandler(st)
checkErr(err)
var listener net.Listener
if cert != "" && key != "" {
cer, err := tls.LoadX509KeyPair(cert, key)
if settings.Server.TLSKey != "" && settings.Server.TLSCert != "" {
cer, err := tls.LoadX509KeyPair(settings.Server.TLSCert, settings.Server.TLSKey)
checkErr(err)
config := &tls.Config{Certificates: []tls.Certificate{cer}}
listener, err = tls.Listen("tcp", addr+":"+strconv.Itoa(port), config)
listener, err = tls.Listen("tcp", settings.Server.Address+":"+strconv.Itoa(settings.Server.Port), config)
checkErr(err)
} else {
listener, err = net.Listen("tcp", addr+":"+strconv.Itoa(port))
listener, err = net.Listen("tcp", settings.Server.Address+":"+strconv.Itoa(settings.Server.Port))
checkErr(err)
}

View File

@ -28,6 +28,12 @@ func mustGetBool(cmd *cobra.Command, flag string) bool {
return b
}
func mustGetInt(cmd *cobra.Command, flag string) int {
b, err := cmd.Flags().GetInt(flag)
checkErr(err)
return b
}
func getDB() *storm.DB {
if _, err := os.Stat(databasePath); err != nil {
panic(errors.New(databasePath + " does not exist. Please run 'filebrowser init' first."))

@ -1 +1 @@
Subproject commit 67832a2bc039398ea3880413dee765a41806b342
Subproject commit 8cb8fd5f6e3eafbe1019916f579e6b4c4771c478

6
go.mod
View File

@ -19,13 +19,13 @@ require (
github.com/gorilla/websocket v1.4.0
github.com/hacdias/fileutils v0.0.0-20171121222743-76b1c6ab9067
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 // indirect
github.com/kr/pretty v0.1.0 // indirect
github.com/maruel/natural v0.0.0-20180416170133-dbcb3e2e8cf1
github.com/mholt/archiver v3.1.0+incompatible
github.com/mholt/caddy v0.11.1
github.com/nwaples/rardecode v1.0.0 // indirect
github.com/pelletier/go-toml v1.2.0
github.com/pierrec/lz4 v2.0.5+incompatible // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spf13/afero v1.1.2
@ -35,7 +35,7 @@ require (
github.com/ulikunitz/xz v0.5.5 // indirect
github.com/vmihailenco/msgpack v4.0.1+incompatible // indirect
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
go.etcd.io/bbolt v1.3.0 // indirect
go.etcd.io/bbolt v1.3.0
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd // indirect
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f // indirect
@ -43,5 +43,5 @@ require (
google.golang.org/appengine v1.3.0 // indirect
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0
gopkg.in/yaml.v2 v2.2.2 // indirect
gopkg.in/yaml.v2 v2.2.2
)

4
go.sum
View File

@ -4,7 +4,6 @@ github.com/DataDog/zstd v1.3.4 h1:LAGHkXuvC6yky+C2CUG2tD7w8QlrUwpue8XwIh0X4AY=
github.com/DataDog/zstd v1.3.4/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/GeertJohan/go.rice v0.0.0-20170420135705-c02ca9a983da h1:UVU3a9pRUyLdnBtn60WjRl0s4SEyJc2ChCY56OAR6wI=
github.com/GeertJohan/go.rice v0.0.0-20170420135705-c02ca9a983da/go.mod h1:DgrzXonpdQbfN3uYaGz1EG4Sbhyum/MMIn6Cphlh2bw=
github.com/NaturalNode/natural v1.0.9 h1:ry8vPQSJc+SvewawAOTzjeZNbYD7AQzmNddCuwqJk4c=
github.com/Sereal/Sereal v0.0.0-20180905114147-563b78806e28 h1:KjLSBawWQq6I0p9VRX8RtHIuttTYvUCGfMgNoBBFxYs=
github.com/Sereal/Sereal v0.0.0-20180905114147-563b78806e28/go.mod h1:D0JMgToj/WdxCgd30Kc1UcA9E+WdZoJqeVOuYW7iTBM=
github.com/asdine/storm v2.1.2+incompatible h1:dczuIkyqwY2LrtXPz8ixMrU/OFgZp71kbKTHGrXYt/Q=
@ -37,8 +36,6 @@ github.com/hacdias/fileutils v0.0.0-20171121222743-76b1c6ab9067 h1:K2ugN3B7NOrAT
github.com/hacdias/fileutils v0.0.0-20171121222743-76b1c6ab9067/go.mod h1:lwnswzFVSy7B/k81M5rOLUU0fOBKHrDRIkPIBZd7PBo=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3 h1:sHsPfNMAG70QAvKbddQ0uScZCHQoZsT5NykGRCeeeIs=
github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s=
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 h1:PJPDf8OUfOK1bb/NeTKd4f1QXZItOX389VN3B6qC8ro=
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
@ -54,6 +51,7 @@ github.com/mholt/caddy v0.11.1 h1:oNfejqftVesLoFxw53Gh17aBPNbTxQ9xJw1pn4IiAPk=
github.com/mholt/caddy v0.11.1/go.mod h1:Wb1PlT4DAYSqOEd03MsqkdkXnTxA8v9pKjdpxbqM1kY=
github.com/nwaples/rardecode v1.0.0 h1:r7vGuS5akxOnR4JQSkko62RJ1ReCMXxQRPtxsiFMBOs=
github.com/nwaples/rardecode v1.0.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

View File

@ -9,6 +9,8 @@ type AuthMethod string
type Settings struct {
Key []byte `json:"key"`
BaseURL string `json:"baseURL"`
Log string `json:"log"`
Server Server `json:"server"`
Signup bool `json:"signup"`
Defaults UserDefaults `json:"defaults"`
AuthMethod AuthMethod `json:"authMethod"`
@ -18,6 +20,14 @@ type Settings struct {
Rules []rules.Rule `json:"rules"` // TODO: use this add to cli
}
// Server settings.
type Server struct {
Port int `json:"port"`
Address string `json:"address"`
TLSCert string `json:"tlsCert"`
TLSKey string `json:"tlsKey"`
}
// GetRules implements rules.Provider.
func (s *Settings) GetRules() []rules.Rule {
return s.Rules

View File

@ -0,0 +1,169 @@
package importer
import (
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
"github.com/filebrowser/filebrowser/auth"
"github.com/filebrowser/filebrowser/users"
"github.com/asdine/storm"
"github.com/filebrowser/filebrowser/settings"
"github.com/filebrowser/filebrowser/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/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/rules"
"github.com/filebrowser/filebrowser/storage"
"github.com/filebrowser/filebrowser/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
}