diff --git a/Dockerfile b/Dockerfile index f73fc582..cb0e8865 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,5 @@ VOLUME /srv EXPOSE 80 COPY filebrowser /filebrowser -COPY docker-entrypoint.sh /entrypoint.sh -ENTRYPOINT [ "/entrypoint.sh" ] -CMD [ "run" ] +ENTRYPOINT [ "/filebrowser"] diff --git a/cmd/cmds_add.go b/cmd/cmds_add.go index eebbe00c..1a6f4ba2 100644 --- a/cmd/cmds_add.go +++ b/cmd/cmds_add.go @@ -1,22 +1,20 @@ package cmd import ( + "strings" + "github.com/spf13/cobra" ) func init() { cmdsCmd.AddCommand(cmdsAddCmd) - cmdsAddCmd.Flags().StringP("command", "c", "", "command to add") - cmdsAddCmd.Flags().StringP("event", "e", "", "corresponding event") - cmdsAddCmd.MarkFlagRequired("command") - cmdsAddCmd.MarkFlagRequired("event") } var cmdsAddCmd = &cobra.Command{ - Use: "add", + Use: "add ", Short: "Add a command to run on a specific event", Long: `Add a command to run on a specific event.`, - Args: cobra.NoArgs, + Args: cobra.MinimumNArgs(2), Run: func(cmd *cobra.Command, args []string) { db := getDB() defer db.Close() @@ -24,10 +22,9 @@ var cmdsAddCmd = &cobra.Command{ s, err := st.Settings.Get() checkErr(err) - evt := mustGetString(cmd, "event") - command := mustGetString(cmd, "command") + command := strings.Join(args[1:], " ") - s.Commands[evt] = append(s.Commands[evt], command) + s.Commands[args[0]] = append(s.Commands[args[0]], command) err = st.Settings.Save(s) checkErr(err) printEvents(s.Commands) diff --git a/cmd/cmds_rm.go b/cmd/cmds_rm.go index 2c19727f..002bdb6a 100644 --- a/cmd/cmds_rm.go +++ b/cmd/cmds_rm.go @@ -1,34 +1,49 @@ package cmd import ( + "strconv" + "github.com/spf13/cobra" ) func init() { cmdsCmd.AddCommand(cmdsRmCmd) - cmdsRmCmd.Flags().StringP("event", "e", "", "corresponding event") - cmdsRmCmd.Flags().UintP("index", "i", 0, "command index") - cmdsRmCmd.MarkFlagRequired("event") - cmdsRmCmd.MarkFlagRequired("index") } var cmdsRmCmd = &cobra.Command{ - Use: "rm", + Use: "rm [index_end]", Short: "Removes a command from an event hooker", Long: `Removes a command from an event hooker.`, - Args: cobra.NoArgs, + Args: func(cmd *cobra.Command, args []string) error { + if err := cobra.RangeArgs(2, 3)(cmd, args); err != nil { + return err + } + + for _, arg := range args[1:] { + if _, err := strconv.Atoi(arg); err != nil { + return err + } + } + + return nil + }, Run: func(cmd *cobra.Command, args []string) { db := getDB() defer db.Close() st := getStorage(db) s, err := st.Settings.Get() checkErr(err) + evt := args[0] - evt := mustGetString(cmd, "event") - i, err := cmd.Flags().GetUint("index") + i, err := strconv.Atoi(args[1]) checkErr(err) + f := i + if len(args) == 3 { + f, err = strconv.Atoi(args[2]) + checkErr(err) + } - s.Commands[evt] = append(s.Commands[evt][:i], s.Commands[evt][i+1:]...) + s.Commands[evt] = append(s.Commands[evt][:i], s.Commands[evt][f+1:]...) err = st.Settings.Save(s) checkErr(err) printEvents(s.Commands) diff --git a/cmd/config.go b/cmd/config.go index bca203c5..4415805e 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -31,7 +31,6 @@ var configCmd = &cobra.Command{ func addConfigFlags(cmd *cobra.Command) { addUserFlags(cmd) - cmd.Flags().StringP("baseURL", "b", "/", "base url of this installation") cmd.Flags().BoolP("signup", "s", false, "allow users to signup") cmd.Flags().String("shell", "", "shell command to which other commands should be appended") @@ -91,7 +90,6 @@ func getAuthentication(cmd *cobra.Command) (settings.AuthMethod, auth.Auther) { func printSettings(s *settings.Settings, auther auth.Auther) { w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) - 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\n", strings.Join(s.Shell, " ")) diff --git a/cmd/config_init.go b/cmd/config_init.go index 6c18628d..64adc137 100644 --- a/cmd/config_init.go +++ b/cmd/config_init.go @@ -9,6 +9,7 @@ import ( "github.com/asdine/storm" "github.com/filebrowser/filebrowser/v2/settings" "github.com/spf13/cobra" + v "github.com/spf13/viper" ) func init() { @@ -27,6 +28,7 @@ to the defaults when creating new users and you don't override the options.`, Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { + databasePath := v.GetString("database") if _, err := os.Stat(databasePath); err == nil { panic(errors.New(databasePath + " already exists")) } @@ -41,7 +43,6 @@ override the options.`, st := getStorage(db) s := &settings.Settings{ Key: generateRandomBytes(64), // 256 bit - BaseURL: mustGetString(cmd, "baseURL"), Signup: mustGetBool(cmd, "signup"), Shell: strings.Split(strings.TrimSpace(mustGetString(cmd, "shell")), " "), AuthMethod: authMethod, diff --git a/cmd/config_set.go b/cmd/config_set.go index b5e7b510..ea0f0159 100644 --- a/cmd/config_set.go +++ b/cmd/config_set.go @@ -30,8 +30,6 @@ you want to change.`, hasAuth := false cmd.Flags().Visit(func(flag *pflag.Flag) { switch flag.Name { - case "baseURL": - s.BaseURL = mustGetString(cmd, flag.Name) case "signup": s.Signup = mustGetBool(cmd, flag.Name) case "auth.method": diff --git a/cmd/import.go b/cmd/import.go index 2dd495cd..3465b64b 100644 --- a/cmd/import.go +++ b/cmd/import.go @@ -3,6 +3,7 @@ package cmd import ( "github.com/filebrowser/filebrowser/v2/storage/bolt/importer" "github.com/spf13/cobra" + v "github.com/spf13/viper" ) func init() { @@ -24,7 +25,7 @@ this version.`, oldDB := mustGetString(cmd, "old.database") oldConf := mustGetString(cmd, "old.config") - err := importer.Import(oldDB, oldConf, databasePath) + err := importer.Import(oldDB, oldConf, v.GetString("database")) checkErr(err) }, } diff --git a/cmd/root.go b/cmd/root.go index 437acf2f..905079b7 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -2,6 +2,7 @@ package cmd import ( "crypto/tls" + "errors" "io/ioutil" "log" "net" @@ -9,46 +10,92 @@ import ( "os" "path/filepath" "strconv" + "strings" "github.com/asdine/storm" "github.com/filebrowser/filebrowser/v2/auth" + fbhttp "github.com/filebrowser/filebrowser/v2/http" "github.com/filebrowser/filebrowser/v2/settings" "github.com/filebrowser/filebrowser/v2/users" - - fbhttp "github.com/filebrowser/filebrowser/v2/http" + "github.com/mitchellh/go-homedir" "github.com/spf13/cobra" + v "github.com/spf13/viper" lumberjack "gopkg.in/natefinch/lumberjack.v2" ) var ( - databasePath string + cfgFile string ) func init() { - rootCmd.PersistentFlags().StringVarP(&databasePath, "database", "d", "./filebrowser.db", "path to the database") + cobra.OnInitialize(initConfig) - rootCmd.Flags().StringP("address", "a", "127.0.0.1", "address to listen on") - rootCmd.Flags().StringP("log", "l", "stdout", "log output") - rootCmd.Flags().IntP("port", "p", 8080, "port to listen on") - rootCmd.Flags().StringP("cert", "c", "", "tls certificate") - rootCmd.Flags().StringP("key", "k", "", "tls key") - rootCmd.Flags().StringP("scope", "s", ".", "scope to prepend to a user's scope when it is relative") + f := rootCmd.Flags() + pf := rootCmd.PersistentFlags() + + pf.StringVarP(&cfgFile, "config", "c", "", "config file path") + vaddP(pf, "database", "d", "./filebrowser.db", "path to the database") + vaddP(f, "address", "a", "127.0.0.1", "address to listen on") + vaddP(f, "log", "l", "stdout", "log output") + vaddP(f, "port", "p", 8080, "port to listen on") + vaddP(f, "cert", "t", "", "tls certificate") + vaddP(f, "key", "k", "", "tls key") + vaddP(f, "scope", "s", ".", "scope to prepend to a user's scope when it is relative") + vaddP(f, "baseurl", "b", "", "base url") + vadd(f, "username", "admin", "username for the first user when using quick config") + vadd(f, "password", "admin", "password for the first user when using quick config") + + if err := v.BindPFlags(f); err != nil { + panic(err) + } + + if err := v.BindPFlags(pf); err != nil { + panic(err) + } } var rootCmd = &cobra.Command{ Use: "filebrowser", Short: "A stylish web-based file browser", Long: `File Browser CLI lets you create the database to use with File Browser, -manage your user and all the configurations without accessing the +manage your users and all the configurations without acessing the web interface. + +If you've never run File Browser, you'll need to have a database for +it. Don't worry: you don't need to setup a separate database server. +We're using Bolt DB which is a single file database and all managed +by ourselves. -If you've never run File Browser, you will need to create the database. -See 'filebrowser help config init' for more information.`, +For this specific command, all the flags you have available (except +"config" for the configuration file), can be given either through +environment variables or configuration files. + +If you don't set "config", it will look for a configuration file called +.filebrowser.{json, toml, yaml, yml} in the following directories: + +- ./ +- $HOME/ +- /etc/filebrowser/ + +The precedence of the configuration values are as follows: + +- flag +- environment variable +- configuration file +- defaults + +The environment variables are prefixed by "FB_" followed by the option +name in caps. So to set "database" via an env variable, you should +set FB_DATABASE equals to the path. + +Also, if the database path doesn't exist, File Browser will enter into +the quick setup mode and a new database will be bootstraped and a new +user created with the credentials from options "username" and "password".`, Run: serveAndListen, } func serveAndListen(cmd *cobra.Command, args []string) { - switch logMethod := mustGetString(cmd, "log"); logMethod { + switch logMethod := v.GetString("log"); logMethod { case "stdout": log.SetOutput(os.Stdout) case "stderr": @@ -64,7 +111,7 @@ func serveAndListen(cmd *cobra.Command, args []string) { }) } - if _, err := os.Stat(databasePath); os.IsNotExist(err) { + if _, err := os.Stat(v.GetString("database")); os.IsNotExist(err) { quickSetup(cmd) } @@ -72,16 +119,22 @@ func serveAndListen(cmd *cobra.Command, args []string) { defer db.Close() st := getStorage(db) - port := mustGetInt(cmd, "port") - address := mustGetString(cmd, "address") - cert := mustGetString(cmd, "cert") - key := mustGetString(cmd, "key") - scope := mustGetString(cmd, "scope") + port := v.GetInt("port") + address := v.GetString("address") + cert := v.GetString("cert") + key := v.GetString("key") + scope := v.GetString("scope") scope, err := filepath.Abs(scope) checkErr(err) settings, err := st.Settings.Get() checkErr(err) + + // Despite Base URL and Scope being "server" type of + // variables, we persist them to the database because + // they are needed during the execution and not only + // to start up the server. + settings.BaseURL = v.GetString("baseurl") settings.Scope = scope err = st.Settings.Save(settings) checkErr(err) @@ -109,13 +162,13 @@ func serveAndListen(cmd *cobra.Command, args []string) { } func quickSetup(cmd *cobra.Command) { - db, err := storm.Open(databasePath) + db, err := storm.Open(v.GetString("database")) checkErr(err) defer db.Close() set := &settings.Settings{ Key: generateRandomBytes(64), // 256 bit - BaseURL: "", + BaseURL: v.GetString("baseurl"), Signup: false, AuthMethod: auth.MethodJSONAuth, Defaults: settings.UserDefaults{ @@ -142,11 +195,17 @@ func quickSetup(cmd *cobra.Command) { err = st.Auth.Save(&auth.JSONAuth{}) checkErr(err) - password, err := users.HashPwd("admin") + username := v.GetString("username") + password := v.GetString("password") + if username == "" || password == "" { + checkErr(errors.New("username and password cannot be empty during quick setup")) + } + + password, err = users.HashPwd(password) checkErr(err) user := &users.User{ - Username: "admin", + Username: username, Password: password, LockPassword: false, } @@ -157,3 +216,28 @@ func quickSetup(cmd *cobra.Command) { err = st.Users.Save(user) checkErr(err) } + +func initConfig() { + if cfgFile == "" { + home, err := homedir.Dir() + checkErr(err) + v.AddConfigPath(".") + v.AddConfigPath(home) + v.AddConfigPath("/etc/filebrowser/") + v.SetConfigName(".filebrowser") + } else { + v.SetConfigFile(cfgFile) + } + + v.SetEnvPrefix("FB") + v.AutomaticEnv() + v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + + if err := v.ReadInConfig(); err != nil { + if _, ok := err.(v.ConfigParseError); ok { + panic(err) + } + // TODO: log.Println("No config file provided") + } + // else TODO: log.Println("Using config file:", v.ConfigFileUsed()) +} diff --git a/cmd/rule_rm.go b/cmd/rule_rm.go index 8b1dda1a..264fdb19 100644 --- a/cmd/rule_rm.go +++ b/cmd/rule_rm.go @@ -1,6 +1,8 @@ package cmd import ( + "strconv" + "github.com/filebrowser/filebrowser/v2/settings" "github.com/filebrowser/filebrowser/v2/storage" "github.com/filebrowser/filebrowser/v2/users" @@ -14,21 +16,39 @@ func init() { } var rulesRmCommand = &cobra.Command{ - Use: "rm", + Use: "rm [index_end]", Short: "Remove a global rule or user rule", Long: `Remove a global rule or user rule.`, - Args: cobra.NoArgs, + Args: func(cmd *cobra.Command, args []string) error { + if err := cobra.RangeArgs(1, 2)(cmd, args); err != nil { + return err + } + + for _, arg := range args { + if _, err := strconv.Atoi(arg); err != nil { + return err + } + } + + return nil + }, Run: func(cmd *cobra.Command, args []string) { - index := mustGetUint(cmd, "index") + i, err := strconv.Atoi(args[0]) + checkErr(err) + f := i + if len(args) == 2 { + f, err = strconv.Atoi(args[1]) + checkErr(err) + } user := func(u *users.User, st *storage.Storage) { - u.Rules = append(u.Rules[:index], u.Rules[index+1:]...) + u.Rules = append(u.Rules[:i], u.Rules[f+1:]...) err := st.Users.Save(u) checkErr(err) } global := func(s *settings.Settings, st *storage.Storage) { - s.Rules = append(s.Rules[:index], s.Rules[index+1:]...) + s.Rules = append(s.Rules[:i], s.Rules[f+1:]...) err := st.Settings.Save(s) checkErr(err) } diff --git a/cmd/rules.go b/cmd/rules.go index 2a7d219d..7a651e53 100644 --- a/cmd/rules.go +++ b/cmd/rules.go @@ -83,9 +83,17 @@ func printRules(rules []rules.Rule, id interface{}) { for id, rule := range rules { fmt.Printf("(%d) ", id) if rule.Regex { - fmt.Printf("Allow: %t\tRegex: %s\n", rule.Allow, rule.Regexp.Raw) + if rule.Allow { + fmt.Printf("Allow Regex: \t%s\n", rule.Regexp.Raw) + } else { + fmt.Printf("Disallow Regex: \t%s\n", rule.Regexp.Raw) + } } else { - fmt.Printf("Allow: %t\tPath: %s\n", rule.Allow, rule.Path) + if rule.Allow { + fmt.Printf("Allow Path: \t%s\n", rule.Path) + } else { + fmt.Printf("Disallow Path: \t%s\n", rule.Path) + } } } } diff --git a/cmd/rules_add.go b/cmd/rules_add.go index 8e982a95..2b25b1e8 100644 --- a/cmd/rules_add.go +++ b/cmd/rules_add.go @@ -1,7 +1,6 @@ package cmd import ( - "errors" "regexp" "github.com/filebrowser/filebrowser/v2/rules" @@ -13,41 +12,33 @@ import ( func init() { rulesCmd.AddCommand(rulesAddCmd) - rulesAddCmd.Flags().BoolP("allow", "a", false, "allow rule instead of disallow") - rulesAddCmd.Flags().StringP("path", "p", "", "path to which the rule applies") - rulesAddCmd.Flags().StringP("regex", "r", "", "regex to which the rule applies") + rulesAddCmd.Flags().BoolP("allow", "a", false, "indicates this is an allow rule") + rulesAddCmd.Flags().BoolP("regex", "r", false, "indicates this is a regex rule") } var rulesAddCmd = &cobra.Command{ - Use: "add", + Use: "add ", Short: "Add a global rule or user rule", - Long: `Add a global rule or user rule. You must -set either path or regex.`, - Args: cobra.NoArgs, + Long: `Add a global rule or user rule.`, + Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { allow := mustGetBool(cmd, "allow") - path := mustGetString(cmd, "path") - regex := mustGetString(cmd, "regex") + regex := mustGetBool(cmd, "regex") + exp := args[0] - if path == "" && regex == "" { - panic(errors.New("you must set either --path or --regex flags")) - } - - if path != "" && regex != "" { - panic(errors.New("you can't set --path and --regex flags at the same time")) - } - - if regex != "" { - regexp.MustCompile(regex) + if regex { + regexp.MustCompile(exp) } rule := rules.Rule{ Allow: allow, - Path: path, - Regex: regex != "", - Regexp: &rules.Regexp{ - Raw: regex, - }, + Regex: regex, + } + + if regex { + rule.Regexp = &rules.Regexp{Raw: exp} + } else { + rule.Path = exp } user := func(u *users.User, st *storage.Storage) { diff --git a/cmd/users.go b/cmd/users.go index 3afdba86..a69199e9 100644 --- a/cmd/users.go +++ b/cmd/users.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "os" + "strconv" "text/tabwriter" "github.com/filebrowser/filebrowser/v2/settings" @@ -53,15 +54,12 @@ func printUsers(users []*users.User) { w.Flush() } -func usernameOrIDRequired(cmd *cobra.Command, args []string) error { - username, _ := cmd.Flags().GetString("username") - id, _ := cmd.Flags().GetUint("id") - - if username == "" && id == 0 { - return errors.New("'username' of 'id' flag required") +func parseUsernameOrID(arg string) (string, uint) { + id, err := strconv.ParseUint(arg, 10, 0) + if err != nil { + return arg, 0 } - - return nil + return "", uint(id) } func addUserFlags(cmd *cobra.Command) { diff --git a/cmd/users_new.go b/cmd/users_add.go similarity index 55% rename from cmd/users_new.go rename to cmd/users_add.go index 47480d65..06906d66 100644 --- a/cmd/users_new.go +++ b/cmd/users_add.go @@ -6,20 +6,15 @@ import ( ) func init() { - usersCmd.AddCommand(usersNewCmd) - - addUserFlags(usersNewCmd) - usersNewCmd.Flags().StringP("username", "u", "", "new users's username") - usersNewCmd.Flags().StringP("password", "p", "", "new user's password") - usersNewCmd.MarkFlagRequired("username") - usersNewCmd.MarkFlagRequired("password") + usersCmd.AddCommand(usersAddCmd) + addUserFlags(usersAddCmd) } -var usersNewCmd = &cobra.Command{ - Use: "new", +var usersAddCmd = &cobra.Command{ + Use: "add ", Short: "Create a new user", Long: `Create a new user and add it to the database.`, - Args: cobra.NoArgs, + Args: cobra.ExactArgs(2), Run: func(cmd *cobra.Command, args []string) { db := getDB() defer db.Close() @@ -29,12 +24,11 @@ var usersNewCmd = &cobra.Command{ checkErr(err) getUserDefaults(cmd, &s.Defaults, false) - password, _ := cmd.Flags().GetString("password") - password, err = users.HashPwd(password) + password, err := users.HashPwd(args[1]) checkErr(err) user := &users.User{ - Username: mustGetString(cmd, "username"), + Username: args[0], Password: password, LockPassword: mustGetBool(cmd, "lockPassword"), } diff --git a/cmd/users_find.go b/cmd/users_find.go index 126c7354..070959c6 100644 --- a/cmd/users_find.go +++ b/cmd/users_find.go @@ -8,15 +8,13 @@ import ( func init() { usersCmd.AddCommand(usersFindCmd) usersCmd.AddCommand(usersLsCmd) - usersFindCmd.Flags().StringP("username", "u", "", "username to find") - usersFindCmd.Flags().UintP("id", "i", 0, "id to find") } var usersFindCmd = &cobra.Command{ - Use: "find", + Use: "find ", Short: "Find a user by username or id", Long: `Find a user by username or id. If no flag is set, all users will be printed.`, - Args: cobra.NoArgs, + Args: cobra.ExactArgs(1), Run: findUsers, } @@ -32,28 +30,25 @@ var findUsers = func(cmd *cobra.Command, args []string) { defer db.Close() st := getStorage(db) - settings, err := st.Settings.Get() - checkErr(err) + var ( + list []*users.User + user *users.User + err error + ) - username, _ := cmd.Flags().GetString("username") - id, _ := cmd.Flags().GetUint("id") + if len(args) == 1 { + username, id := parseUsernameOrID(args[0]) + if username != "" { + user, err = st.Users.Get("", username) + } else { + user, err = st.Users.Get("", id) + } - var list []*users.User - var user *users.User - - if username != "" { - user, err = st.Users.Get(settings.Scope, username) - } else if id != 0 { - user, err = st.Users.Get(settings.Scope, id) - } else { - list, err = st.Users.Gets(settings.Scope) - } - - checkErr(err) - - if user != nil { list = []*users.User{user} + } else { + list, err = st.Users.Gets("") } + checkErr(err) printUsers(list) } diff --git a/cmd/users_rm.go b/cmd/users_rm.go index 5f1b5eb6..e942c62b 100644 --- a/cmd/users_rm.go +++ b/cmd/users_rm.go @@ -8,23 +8,19 @@ import ( func init() { usersCmd.AddCommand(usersRmCmd) - usersRmCmd.Flags().StringP("username", "u", "", "username to delete") - usersRmCmd.Flags().UintP("id", "i", 0, "id to delete") } var usersRmCmd = &cobra.Command{ - Use: "rm", + Use: "rm ", Short: "Delete a user by username or id", Long: `Delete a user by username or id`, - Args: usernameOrIDRequired, + Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { db := getDB() defer db.Close() st := getStorage(db) - username, _ := cmd.Flags().GetString("username") - id, _ := cmd.Flags().GetUint("id") - + username, id := parseUsernameOrID(args[0]) var err error if username != "" { diff --git a/cmd/users_update.go b/cmd/users_update.go index f0aa27ba..fb6f65a5 100644 --- a/cmd/users_update.go +++ b/cmd/users_update.go @@ -9,18 +9,17 @@ import ( func init() { usersCmd.AddCommand(usersUpdateCmd) - usersUpdateCmd.Flags().UintP("id", "i", 0, "id of the user") - usersUpdateCmd.Flags().StringP("username", "u", "", "user to change or new username if flag 'id' is set") usersUpdateCmd.Flags().StringP("password", "p", "", "new password") + usersUpdateCmd.Flags().StringP("username", "u", "", "new username") addUserFlags(usersUpdateCmd) } var usersUpdateCmd = &cobra.Command{ - Use: "update", + Use: "update ", Short: "Updates an existing user", Long: `Updates an existing user. Set the flags for the options you want to change.`, - Args: usernameOrIDRequired, + Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { db := getDB() defer db.Close() @@ -29,9 +28,9 @@ options you want to change.`, set, err := st.Settings.Get() checkErr(err) - id, _ := cmd.Flags().GetUint("id") - username := mustGetString(cmd, "username") + username, id := parseUsernameOrID(args[0]) password := mustGetString(cmd, "password") + newUsername := mustGetString(cmd, "username") var user *users.User @@ -60,8 +59,8 @@ options you want to change.`, user.Sorting = defaults.Sorting user.LockPassword = mustGetBool(cmd, "lockPassword") - if user.Username != username && username != "" { - user.Username = username + if newUsername != "" { + user.Username = newUsername } if password != "" { diff --git a/cmd/utils.go b/cmd/utils.go index 70e63413..b5f84915 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -9,8 +9,34 @@ import ( "github.com/filebrowser/filebrowser/v2/storage" "github.com/filebrowser/filebrowser/v2/storage/bolt" "github.com/spf13/cobra" + "github.com/spf13/pflag" + v "github.com/spf13/viper" ) +func vaddP(f *pflag.FlagSet, k, p string, i interface{}, u string) { + switch y := i.(type) { + case bool: + f.BoolP(k, p, y, u) + case int: + f.IntP(k, p, y, u) + case string: + f.StringP(k, p, y, u) + } + v.SetDefault(k, i) +} + +func vadd(f *pflag.FlagSet, k string, i interface{}, u string) { + switch y := i.(type) { + case bool: + f.Bool(k, y, u) + case int: + f.Int(k, y, u) + case string: + f.String(k, y, u) + } + v.SetDefault(k, i) +} + func checkErr(err error) { if err != nil { panic(err) @@ -29,12 +55,6 @@ 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 mustGetUint(cmd *cobra.Command, flag string) uint { b, err := cmd.Flags().GetUint(flag) checkErr(err) @@ -42,6 +62,7 @@ func mustGetUint(cmd *cobra.Command, flag string) uint { } func getDB() *storm.DB { + databasePath := v.GetString("database") if _, err := os.Stat(databasePath); err != nil { panic(errors.New(databasePath + " does not exist. Please run 'filebrowser init' first.")) } diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh deleted file mode 100644 index 2a3b7ffb..00000000 --- a/docker-entrypoint.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh - -set -e - -if [ "$1" = 'run' ]; then - if [ ! -f "/database.db" ]; then - filebrowser -s /src - fi - - exec filemanager --port 80 -fi - -exec filemanager --port 80 "$@" diff --git a/go.mod b/go.mod index 08b1a00c..cb9c2a2b 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,6 @@ require ( github.com/asdine/storm v2.1.2+incompatible github.com/boltdb/bolt v1.3.1 // indirect github.com/daaku/go.zipexe v0.0.0-20150329023125-a5fe2436ffcb // indirect - github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/dsnet/compress v0.0.0-20171208185109-cc9eb1d7ad76 // indirect github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect @@ -24,14 +23,14 @@ require ( 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/mitchellh/go-homedir v1.0.0 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 github.com/spf13/cobra v0.0.3 github.com/spf13/pflag v1.0.3 - github.com/stretchr/testify v1.2.2 // indirect + github.com/spf13/viper v1.3.1 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 @@ -39,7 +38,6 @@ require ( 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 - golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a // indirect 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 diff --git a/go.sum b/go.sum index 7b355bef..c6b3e08d 100644 --- a/go.sum +++ b/go.sum @@ -6,10 +6,14 @@ github.com/GeertJohan/go.rice v0.0.0-20170420135705-c02ca9a983da h1:UVU3a9pRUyLd github.com/GeertJohan/go.rice v0.0.0-20170420135705-c02ca9a983da/go.mod h1:DgrzXonpdQbfN3uYaGz1EG4Sbhyum/MMIn6Cphlh2bw= 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/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/asdine/storm v2.1.2+incompatible h1:dczuIkyqwY2LrtXPz8ixMrU/OFgZp71kbKTHGrXYt/Q= github.com/asdine/storm v2.1.2+incompatible/go.mod h1:RarYDc9hq1UPLImuiXK3BIWPJLdIygvV3PsInK0FbVQ= github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/daaku/go.zipexe v0.0.0-20150329023125-a5fe2436ffcb h1:tUf55Po0vzOendQ7NWytcdK0VuzQmfAgvGBUOQvN0WA= github.com/daaku/go.zipexe v0.0.0-20150329023125-a5fe2436ffcb/go.mod h1:U0vRfAucUOohvdCxt5MWLF+TePIL0xbCkbKIiV8TQCE= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -20,6 +24,8 @@ github.com/dsnet/compress v0.0.0-20171208185109-cc9eb1d7ad76 h1:eX+pdPPlD279OWgd github.com/dsnet/compress v0.0.0-20171208185109-cc9eb1d7ad76/go.mod h1:KjxHHirfLaw19iGT70HvVjHQsL1vq1SRQB4yOsAfy2s= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= @@ -34,6 +40,8 @@ github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/hacdias/fileutils v0.0.0-20171121222743-76b1c6ab9067 h1:K2ugN3B7NOrATI7GfXRrwtbyg0OYVR9oNcm1XeTIyY4= github.com/hacdias/fileutils v0.0.0-20171121222743-76b1c6ab9067/go.mod h1:lwnswzFVSy7B/k81M5rOLUU0fOBKHrDRIkPIBZd7PBo= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 h1:PJPDf8OUfOK1bb/NeTKd4f1QXZItOX389VN3B6qC8ro= @@ -43,12 +51,18 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/maruel/natural v0.0.0-20180416170133-dbcb3e2e8cf1 h1:PEhRT94KBTY4E0KdCYmhvDGWjSFBxc68j2M6PMRix8U= github.com/maruel/natural v0.0.0-20180416170133-dbcb3e2e8cf1/go.mod h1:wI697HNhDFM/vBruYM3ckbszQ2+DOIeH9qdBKMdf288= github.com/mholt/archiver v3.1.0+incompatible h1:S1rFZ7umHtN6cG+6cusrfoXTMPqp6u/R89iKxBYJd4w= github.com/mholt/archiver v3.1.0+incompatible/go.mod h1:Dh2dOXnSdiLxRiPoVfIr/fI1TwETms9B8CTWfeh7ROU= github.com/mholt/caddy v0.11.1 h1:oNfejqftVesLoFxw53Gh17aBPNbTxQ9xJw1pn4IiAPk= github.com/mholt/caddy v0.11.1/go.mod h1:Wb1PlT4DAYSqOEd03MsqkdkXnTxA8v9pKjdpxbqM1kY= +github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 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 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= @@ -59,18 +73,26 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.1 h1:5+8j8FTpnFV4nEImW/ofkzEt8VoOiLXxdYIDsB73T38= +github.com/spf13/viper v1.3.1/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok= github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= github.com/vmihailenco/msgpack v4.0.1+incompatible h1:RMF1enSPeKTlXrXdOcqjFUElywVZjjC6pqse21bKbEU= github.com/vmihailenco/msgpack v4.0.1+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= go.etcd.io/bbolt v1.3.0 h1:oY10fI923Q5pVCVt1GBTZMn8LHo5M+RCInFpeMnV4QI= go.etcd.io/bbolt v1.3.0/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 h1:mKdxBk7AujPs8kU4m80U72y/zjbZ3UcXC7dClwKbUI0=