diff --git a/cmd/config.go b/cmd/config.go index d21c95d3..9d23e973 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -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) diff --git a/cmd/config_init.go b/cmd/config_init.go index d58e6e2f..fa237ef5 100644 --- a/cmd/config_init.go +++ b/cmd/config_init.go @@ -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) diff --git a/cmd/config_set.go b/cmd/config_set.go index 96c80578..4bbeefe9 100644 --- a/cmd/config_set.go +++ b/cmd/config_set.go @@ -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) } }) diff --git a/cmd/import.go b/cmd/import.go new file mode 100644 index 00000000..1f87fbbc --- /dev/null +++ b/cmd/import.go @@ -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) + }, +} diff --git a/cmd/root.go b/cmd/root.go index 78279eb0..22cf6689 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -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) } diff --git a/cmd/utils.go b/cmd/utils.go index c7506bcd..15112fef 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -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.")) diff --git a/frontend b/frontend index 67832a2b..8cb8fd5f 160000 --- a/frontend +++ b/frontend @@ -1 +1 @@ -Subproject commit 67832a2bc039398ea3880413dee765a41806b342 +Subproject commit 8cb8fd5f6e3eafbe1019916f579e6b4c4771c478 diff --git a/go.mod b/go.mod index dabdf560..9341d944 100644 --- a/go.mod +++ b/go.mod @@ -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 ) diff --git a/go.sum b/go.sum index 17517a3e..bdaa211d 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/settings/settings.go b/settings/settings.go index 9318027d..8fe757d8 100644 --- a/settings/settings.go +++ b/settings/settings.go @@ -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 diff --git a/storage/bolt/importer/conf.go b/storage/bolt/importer/conf.go new file mode 100644 index 00000000..c9391165 --- /dev/null +++ b/storage/bolt/importer/conf.go @@ -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 +} diff --git a/storage/bolt/importer/importer.go b/storage/bolt/importer/importer.go new file mode 100644 index 00000000..e06a6100 --- /dev/null +++ b/storage/bolt/importer/importer.go @@ -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 +} diff --git a/storage/bolt/importer/users.go b/storage/bolt/importer/users.go new file mode 100644 index 00000000..677f2cee --- /dev/null +++ b/storage/bolt/importer/users.go @@ -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 +}