Merge pull request #606 from filebrowser/viper

feat: dockerfile & viper
This commit is contained in:
Henrique Dias 2019-01-06 15:27:23 +00:00 committed by GitHub
commit 143dcec6f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 285 additions and 164 deletions

View File

@ -7,7 +7,5 @@ VOLUME /srv
EXPOSE 80 EXPOSE 80
COPY filebrowser /filebrowser COPY filebrowser /filebrowser
COPY docker-entrypoint.sh /entrypoint.sh
ENTRYPOINT [ "/entrypoint.sh" ] ENTRYPOINT [ "/filebrowser"]
CMD [ "run" ]

View File

@ -1,22 +1,20 @@
package cmd package cmd
import ( import (
"strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func init() { func init() {
cmdsCmd.AddCommand(cmdsAddCmd) 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{ var cmdsAddCmd = &cobra.Command{
Use: "add", Use: "add <event> <command>",
Short: "Add a command to run on a specific event", Short: "Add a command to run on a specific event",
Long: `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) { Run: func(cmd *cobra.Command, args []string) {
db := getDB() db := getDB()
defer db.Close() defer db.Close()
@ -24,10 +22,9 @@ var cmdsAddCmd = &cobra.Command{
s, err := st.Settings.Get() s, err := st.Settings.Get()
checkErr(err) checkErr(err)
evt := mustGetString(cmd, "event") command := strings.Join(args[1:], " ")
command := mustGetString(cmd, "command")
s.Commands[evt] = append(s.Commands[evt], command) s.Commands[args[0]] = append(s.Commands[args[0]], command)
err = st.Settings.Save(s) err = st.Settings.Save(s)
checkErr(err) checkErr(err)
printEvents(s.Commands) printEvents(s.Commands)

View File

@ -1,34 +1,49 @@
package cmd package cmd
import ( import (
"strconv"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func init() { func init() {
cmdsCmd.AddCommand(cmdsRmCmd) 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{ var cmdsRmCmd = &cobra.Command{
Use: "rm", Use: "rm <event> <index> [index_end]",
Short: "Removes a command from an event hooker", Short: "Removes a command from an event hooker",
Long: `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) { Run: func(cmd *cobra.Command, args []string) {
db := getDB() db := getDB()
defer db.Close() defer db.Close()
st := getStorage(db) st := getStorage(db)
s, err := st.Settings.Get() s, err := st.Settings.Get()
checkErr(err) checkErr(err)
evt := args[0]
evt := mustGetString(cmd, "event") i, err := strconv.Atoi(args[1])
i, err := cmd.Flags().GetUint("index")
checkErr(err) 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) err = st.Settings.Save(s)
checkErr(err) checkErr(err)
printEvents(s.Commands) printEvents(s.Commands)

View File

@ -31,7 +31,6 @@ var configCmd = &cobra.Command{
func addConfigFlags(cmd *cobra.Command) { func addConfigFlags(cmd *cobra.Command) {
addUserFlags(cmd) addUserFlags(cmd)
cmd.Flags().StringP("baseURL", "b", "/", "base url of this installation")
cmd.Flags().BoolP("signup", "s", false, "allow users to signup") 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().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) { func printSettings(s *settings.Settings, auther auth.Auther) {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) 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, "Sign up:\t%t\n", s.Signup)
fmt.Fprintf(w, "Auth method:\t%s\n", s.AuthMethod) fmt.Fprintf(w, "Auth method:\t%s\n", s.AuthMethod)
fmt.Fprintf(w, "Shell:\t%s\t\n", strings.Join(s.Shell, " ")) fmt.Fprintf(w, "Shell:\t%s\t\n", strings.Join(s.Shell, " "))

View File

@ -9,6 +9,7 @@ import (
"github.com/asdine/storm" "github.com/asdine/storm"
"github.com/filebrowser/filebrowser/v2/settings" "github.com/filebrowser/filebrowser/v2/settings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
v "github.com/spf13/viper"
) )
func init() { func init() {
@ -27,6 +28,7 @@ to the defaults when creating new users and you don't
override the options.`, override the options.`,
Args: cobra.NoArgs, Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
databasePath := v.GetString("database")
if _, err := os.Stat(databasePath); err == nil { if _, err := os.Stat(databasePath); err == nil {
panic(errors.New(databasePath + " already exists")) panic(errors.New(databasePath + " already exists"))
} }
@ -41,7 +43,6 @@ override the options.`,
st := getStorage(db) st := getStorage(db)
s := &settings.Settings{ s := &settings.Settings{
Key: generateRandomBytes(64), // 256 bit Key: generateRandomBytes(64), // 256 bit
BaseURL: mustGetString(cmd, "baseURL"),
Signup: mustGetBool(cmd, "signup"), Signup: mustGetBool(cmd, "signup"),
Shell: strings.Split(strings.TrimSpace(mustGetString(cmd, "shell")), " "), Shell: strings.Split(strings.TrimSpace(mustGetString(cmd, "shell")), " "),
AuthMethod: authMethod, AuthMethod: authMethod,

View File

@ -30,8 +30,6 @@ you want to change.`,
hasAuth := false hasAuth := false
cmd.Flags().Visit(func(flag *pflag.Flag) { cmd.Flags().Visit(func(flag *pflag.Flag) {
switch flag.Name { switch flag.Name {
case "baseURL":
s.BaseURL = mustGetString(cmd, flag.Name)
case "signup": case "signup":
s.Signup = mustGetBool(cmd, flag.Name) s.Signup = mustGetBool(cmd, flag.Name)
case "auth.method": case "auth.method":

View File

@ -3,6 +3,7 @@ package cmd
import ( import (
"github.com/filebrowser/filebrowser/v2/storage/bolt/importer" "github.com/filebrowser/filebrowser/v2/storage/bolt/importer"
"github.com/spf13/cobra" "github.com/spf13/cobra"
v "github.com/spf13/viper"
) )
func init() { func init() {
@ -24,7 +25,7 @@ this version.`,
oldDB := mustGetString(cmd, "old.database") oldDB := mustGetString(cmd, "old.database")
oldConf := mustGetString(cmd, "old.config") oldConf := mustGetString(cmd, "old.config")
err := importer.Import(oldDB, oldConf, databasePath) err := importer.Import(oldDB, oldConf, v.GetString("database"))
checkErr(err) checkErr(err)
}, },
} }

View File

@ -2,6 +2,7 @@ package cmd
import ( import (
"crypto/tls" "crypto/tls"
"errors"
"io/ioutil" "io/ioutil"
"log" "log"
"net" "net"
@ -9,46 +10,92 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings"
"github.com/asdine/storm" "github.com/asdine/storm"
"github.com/filebrowser/filebrowser/v2/auth" "github.com/filebrowser/filebrowser/v2/auth"
fbhttp "github.com/filebrowser/filebrowser/v2/http"
"github.com/filebrowser/filebrowser/v2/settings" "github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/users" "github.com/filebrowser/filebrowser/v2/users"
"github.com/mitchellh/go-homedir"
fbhttp "github.com/filebrowser/filebrowser/v2/http"
"github.com/spf13/cobra" "github.com/spf13/cobra"
v "github.com/spf13/viper"
lumberjack "gopkg.in/natefinch/lumberjack.v2" lumberjack "gopkg.in/natefinch/lumberjack.v2"
) )
var ( var (
databasePath string cfgFile string
) )
func init() { 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") f := rootCmd.Flags()
rootCmd.Flags().StringP("log", "l", "stdout", "log output") pf := rootCmd.PersistentFlags()
rootCmd.Flags().IntP("port", "p", 8080, "port to listen on")
rootCmd.Flags().StringP("cert", "c", "", "tls certificate") pf.StringVarP(&cfgFile, "config", "c", "", "config file path")
rootCmd.Flags().StringP("key", "k", "", "tls key") vaddP(pf, "database", "d", "./filebrowser.db", "path to the database")
rootCmd.Flags().StringP("scope", "s", ".", "scope to prepend to a user's scope when it is relative") 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{ var rootCmd = &cobra.Command{
Use: "filebrowser", Use: "filebrowser",
Short: "A stylish web-based file browser", Short: "A stylish web-based file browser",
Long: `File Browser CLI lets you create the database to use with 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. web interface.
If you've never run File Browser, you will need to create the database. If you've never run File Browser, you'll need to have a database for
See 'filebrowser help config init' for more information.`, 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.
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, Run: serveAndListen,
} }
func serveAndListen(cmd *cobra.Command, args []string) { func serveAndListen(cmd *cobra.Command, args []string) {
switch logMethod := mustGetString(cmd, "log"); logMethod { switch logMethod := v.GetString("log"); logMethod {
case "stdout": case "stdout":
log.SetOutput(os.Stdout) log.SetOutput(os.Stdout)
case "stderr": 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) quickSetup(cmd)
} }
@ -72,16 +119,22 @@ func serveAndListen(cmd *cobra.Command, args []string) {
defer db.Close() defer db.Close()
st := getStorage(db) st := getStorage(db)
port := mustGetInt(cmd, "port") port := v.GetInt("port")
address := mustGetString(cmd, "address") address := v.GetString("address")
cert := mustGetString(cmd, "cert") cert := v.GetString("cert")
key := mustGetString(cmd, "key") key := v.GetString("key")
scope := mustGetString(cmd, "scope") scope := v.GetString("scope")
scope, err := filepath.Abs(scope) scope, err := filepath.Abs(scope)
checkErr(err) checkErr(err)
settings, err := st.Settings.Get() settings, err := st.Settings.Get()
checkErr(err) 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 settings.Scope = scope
err = st.Settings.Save(settings) err = st.Settings.Save(settings)
checkErr(err) checkErr(err)
@ -109,13 +162,13 @@ func serveAndListen(cmd *cobra.Command, args []string) {
} }
func quickSetup(cmd *cobra.Command) { func quickSetup(cmd *cobra.Command) {
db, err := storm.Open(databasePath) db, err := storm.Open(v.GetString("database"))
checkErr(err) checkErr(err)
defer db.Close() defer db.Close()
set := &settings.Settings{ set := &settings.Settings{
Key: generateRandomBytes(64), // 256 bit Key: generateRandomBytes(64), // 256 bit
BaseURL: "", BaseURL: v.GetString("baseurl"),
Signup: false, Signup: false,
AuthMethod: auth.MethodJSONAuth, AuthMethod: auth.MethodJSONAuth,
Defaults: settings.UserDefaults{ Defaults: settings.UserDefaults{
@ -142,11 +195,17 @@ func quickSetup(cmd *cobra.Command) {
err = st.Auth.Save(&auth.JSONAuth{}) err = st.Auth.Save(&auth.JSONAuth{})
checkErr(err) 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) checkErr(err)
user := &users.User{ user := &users.User{
Username: "admin", Username: username,
Password: password, Password: password,
LockPassword: false, LockPassword: false,
} }
@ -157,3 +216,28 @@ func quickSetup(cmd *cobra.Command) {
err = st.Users.Save(user) err = st.Users.Save(user)
checkErr(err) 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())
}

View File

@ -1,6 +1,8 @@
package cmd package cmd
import ( import (
"strconv"
"github.com/filebrowser/filebrowser/v2/settings" "github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/storage" "github.com/filebrowser/filebrowser/v2/storage"
"github.com/filebrowser/filebrowser/v2/users" "github.com/filebrowser/filebrowser/v2/users"
@ -14,21 +16,39 @@ func init() {
} }
var rulesRmCommand = &cobra.Command{ var rulesRmCommand = &cobra.Command{
Use: "rm", Use: "rm <index> [index_end]",
Short: "Remove a global rule or user rule", Short: "Remove a global rule or user rule",
Long: `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) { 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) { 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) err := st.Users.Save(u)
checkErr(err) checkErr(err)
} }
global := func(s *settings.Settings, st *storage.Storage) { 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) err := st.Settings.Save(s)
checkErr(err) checkErr(err)
} }

View File

@ -83,9 +83,17 @@ func printRules(rules []rules.Rule, id interface{}) {
for id, rule := range rules { for id, rule := range rules {
fmt.Printf("(%d) ", id) fmt.Printf("(%d) ", id)
if rule.Regex { 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 { } else {
fmt.Printf("Allow: %t\tPath: %s\n", rule.Allow, rule.Path) fmt.Printf("Disallow Regex: \t%s\n", rule.Regexp.Raw)
}
} else {
if rule.Allow {
fmt.Printf("Allow Path: \t%s\n", rule.Path)
} else {
fmt.Printf("Disallow Path: \t%s\n", rule.Path)
}
} }
} }
} }

View File

@ -1,7 +1,6 @@
package cmd package cmd
import ( import (
"errors"
"regexp" "regexp"
"github.com/filebrowser/filebrowser/v2/rules" "github.com/filebrowser/filebrowser/v2/rules"
@ -13,41 +12,33 @@ import (
func init() { func init() {
rulesCmd.AddCommand(rulesAddCmd) rulesCmd.AddCommand(rulesAddCmd)
rulesAddCmd.Flags().BoolP("allow", "a", false, "allow rule instead of disallow") rulesAddCmd.Flags().BoolP("allow", "a", false, "indicates this is an allow rule")
rulesAddCmd.Flags().StringP("path", "p", "", "path to which the rule applies") rulesAddCmd.Flags().BoolP("regex", "r", false, "indicates this is a regex rule")
rulesAddCmd.Flags().StringP("regex", "r", "", "regex to which the rule applies")
} }
var rulesAddCmd = &cobra.Command{ var rulesAddCmd = &cobra.Command{
Use: "add", Use: "add <path|expression>",
Short: "Add a global rule or user rule", Short: "Add a global rule or user rule",
Long: `Add a global rule or user rule. You must Long: `Add a global rule or user rule.`,
set either path or regex.`, Args: cobra.ExactArgs(1),
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
allow := mustGetBool(cmd, "allow") allow := mustGetBool(cmd, "allow")
path := mustGetString(cmd, "path") regex := mustGetBool(cmd, "regex")
regex := mustGetString(cmd, "regex") exp := args[0]
if path == "" && regex == "" { if regex {
panic(errors.New("you must set either --path or --regex flags")) regexp.MustCompile(exp)
}
if path != "" && regex != "" {
panic(errors.New("you can't set --path and --regex flags at the same time"))
}
if regex != "" {
regexp.MustCompile(regex)
} }
rule := rules.Rule{ rule := rules.Rule{
Allow: allow, Allow: allow,
Path: path, Regex: regex,
Regex: regex != "", }
Regexp: &rules.Regexp{
Raw: regex, if regex {
}, rule.Regexp = &rules.Regexp{Raw: exp}
} else {
rule.Path = exp
} }
user := func(u *users.User, st *storage.Storage) { user := func(u *users.User, st *storage.Storage) {

View File

@ -4,6 +4,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"os" "os"
"strconv"
"text/tabwriter" "text/tabwriter"
"github.com/filebrowser/filebrowser/v2/settings" "github.com/filebrowser/filebrowser/v2/settings"
@ -53,15 +54,12 @@ func printUsers(users []*users.User) {
w.Flush() w.Flush()
} }
func usernameOrIDRequired(cmd *cobra.Command, args []string) error { func parseUsernameOrID(arg string) (string, uint) {
username, _ := cmd.Flags().GetString("username") id, err := strconv.ParseUint(arg, 10, 0)
id, _ := cmd.Flags().GetUint("id") if err != nil {
return arg, 0
if username == "" && id == 0 {
return errors.New("'username' of 'id' flag required")
} }
return "", uint(id)
return nil
} }
func addUserFlags(cmd *cobra.Command) { func addUserFlags(cmd *cobra.Command) {

View File

@ -6,20 +6,15 @@ import (
) )
func init() { func init() {
usersCmd.AddCommand(usersNewCmd) usersCmd.AddCommand(usersAddCmd)
addUserFlags(usersAddCmd)
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")
} }
var usersNewCmd = &cobra.Command{ var usersAddCmd = &cobra.Command{
Use: "new", Use: "add <username> <password>",
Short: "Create a new user", Short: "Create a new user",
Long: `Create a new user and add it to the database.`, 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) { Run: func(cmd *cobra.Command, args []string) {
db := getDB() db := getDB()
defer db.Close() defer db.Close()
@ -29,12 +24,11 @@ var usersNewCmd = &cobra.Command{
checkErr(err) checkErr(err)
getUserDefaults(cmd, &s.Defaults, false) getUserDefaults(cmd, &s.Defaults, false)
password, _ := cmd.Flags().GetString("password") password, err := users.HashPwd(args[1])
password, err = users.HashPwd(password)
checkErr(err) checkErr(err)
user := &users.User{ user := &users.User{
Username: mustGetString(cmd, "username"), Username: args[0],
Password: password, Password: password,
LockPassword: mustGetBool(cmd, "lockPassword"), LockPassword: mustGetBool(cmd, "lockPassword"),
} }

View File

@ -8,15 +8,13 @@ import (
func init() { func init() {
usersCmd.AddCommand(usersFindCmd) usersCmd.AddCommand(usersFindCmd)
usersCmd.AddCommand(usersLsCmd) usersCmd.AddCommand(usersLsCmd)
usersFindCmd.Flags().StringP("username", "u", "", "username to find")
usersFindCmd.Flags().UintP("id", "i", 0, "id to find")
} }
var usersFindCmd = &cobra.Command{ var usersFindCmd = &cobra.Command{
Use: "find", Use: "find <id|username>",
Short: "Find a user by username or id", 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.`, 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, Run: findUsers,
} }
@ -32,28 +30,25 @@ var findUsers = func(cmd *cobra.Command, args []string) {
defer db.Close() defer db.Close()
st := getStorage(db) st := getStorage(db)
settings, err := st.Settings.Get() var (
checkErr(err) list []*users.User
user *users.User
username, _ := cmd.Flags().GetString("username") err error
id, _ := cmd.Flags().GetUint("id") )
var list []*users.User
var user *users.User
if len(args) == 1 {
username, id := parseUsernameOrID(args[0])
if username != "" { if username != "" {
user, err = st.Users.Get(settings.Scope, username) user, err = st.Users.Get("", username)
} else if id != 0 {
user, err = st.Users.Get(settings.Scope, id)
} else { } else {
list, err = st.Users.Gets(settings.Scope) user, err = st.Users.Get("", id)
}
list = []*users.User{user}
} else {
list, err = st.Users.Gets("")
} }
checkErr(err) checkErr(err)
if user != nil {
list = []*users.User{user}
}
printUsers(list) printUsers(list)
} }

View File

@ -8,23 +8,19 @@ import (
func init() { func init() {
usersCmd.AddCommand(usersRmCmd) usersCmd.AddCommand(usersRmCmd)
usersRmCmd.Flags().StringP("username", "u", "", "username to delete")
usersRmCmd.Flags().UintP("id", "i", 0, "id to delete")
} }
var usersRmCmd = &cobra.Command{ var usersRmCmd = &cobra.Command{
Use: "rm", Use: "rm <id|username>",
Short: "Delete a user by username or id", Short: "Delete a user by username or id",
Long: `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) { Run: func(cmd *cobra.Command, args []string) {
db := getDB() db := getDB()
defer db.Close() defer db.Close()
st := getStorage(db) st := getStorage(db)
username, _ := cmd.Flags().GetString("username") username, id := parseUsernameOrID(args[0])
id, _ := cmd.Flags().GetUint("id")
var err error var err error
if username != "" { if username != "" {

View File

@ -9,18 +9,17 @@ import (
func init() { func init() {
usersCmd.AddCommand(usersUpdateCmd) 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("password", "p", "", "new password")
usersUpdateCmd.Flags().StringP("username", "u", "", "new username")
addUserFlags(usersUpdateCmd) addUserFlags(usersUpdateCmd)
} }
var usersUpdateCmd = &cobra.Command{ var usersUpdateCmd = &cobra.Command{
Use: "update", Use: "update <id|username>",
Short: "Updates an existing user", Short: "Updates an existing user",
Long: `Updates an existing user. Set the flags for the Long: `Updates an existing user. Set the flags for the
options you want to change.`, options you want to change.`,
Args: usernameOrIDRequired, Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
db := getDB() db := getDB()
defer db.Close() defer db.Close()
@ -29,9 +28,9 @@ options you want to change.`,
set, err := st.Settings.Get() set, err := st.Settings.Get()
checkErr(err) checkErr(err)
id, _ := cmd.Flags().GetUint("id") username, id := parseUsernameOrID(args[0])
username := mustGetString(cmd, "username")
password := mustGetString(cmd, "password") password := mustGetString(cmd, "password")
newUsername := mustGetString(cmd, "username")
var user *users.User var user *users.User
@ -60,8 +59,8 @@ options you want to change.`,
user.Sorting = defaults.Sorting user.Sorting = defaults.Sorting
user.LockPassword = mustGetBool(cmd, "lockPassword") user.LockPassword = mustGetBool(cmd, "lockPassword")
if user.Username != username && username != "" { if newUsername != "" {
user.Username = username user.Username = newUsername
} }
if password != "" { if password != "" {

View File

@ -9,8 +9,34 @@ import (
"github.com/filebrowser/filebrowser/v2/storage" "github.com/filebrowser/filebrowser/v2/storage"
"github.com/filebrowser/filebrowser/v2/storage/bolt" "github.com/filebrowser/filebrowser/v2/storage/bolt"
"github.com/spf13/cobra" "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) { func checkErr(err error) {
if err != nil { if err != nil {
panic(err) panic(err)
@ -29,12 +55,6 @@ func mustGetBool(cmd *cobra.Command, flag string) bool {
return b 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 { func mustGetUint(cmd *cobra.Command, flag string) uint {
b, err := cmd.Flags().GetUint(flag) b, err := cmd.Flags().GetUint(flag)
checkErr(err) checkErr(err)
@ -42,6 +62,7 @@ func mustGetUint(cmd *cobra.Command, flag string) uint {
} }
func getDB() *storm.DB { func getDB() *storm.DB {
databasePath := v.GetString("database")
if _, err := os.Stat(databasePath); err != nil { if _, err := os.Stat(databasePath); err != nil {
panic(errors.New(databasePath + " does not exist. Please run 'filebrowser init' first.")) panic(errors.New(databasePath + " does not exist. Please run 'filebrowser init' first."))
} }

View File

@ -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 "$@"

6
go.mod
View File

@ -8,7 +8,6 @@ require (
github.com/asdine/storm v2.1.2+incompatible github.com/asdine/storm v2.1.2+incompatible
github.com/boltdb/bolt v1.3.1 // indirect github.com/boltdb/bolt v1.3.1 // indirect
github.com/daaku/go.zipexe v0.0.0-20150329023125-a5fe2436ffcb // 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/dgrijalva/jwt-go v3.2.0+incompatible
github.com/dsnet/compress v0.0.0-20171208185109-cc9eb1d7ad76 // indirect github.com/dsnet/compress v0.0.0-20171208185109-cc9eb1d7ad76 // indirect
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // 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/maruel/natural v0.0.0-20180416170133-dbcb3e2e8cf1
github.com/mholt/archiver v3.1.0+incompatible github.com/mholt/archiver v3.1.0+incompatible
github.com/mholt/caddy v0.11.1 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/nwaples/rardecode v1.0.0 // indirect
github.com/pelletier/go-toml v1.2.0 github.com/pelletier/go-toml v1.2.0
github.com/pierrec/lz4 v2.0.5+incompatible // indirect 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/afero v1.1.2
github.com/spf13/cobra v0.0.3 github.com/spf13/cobra v0.0.3
github.com/spf13/pflag v1.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/ulikunitz/xz v0.5.5 // indirect
github.com/vmihailenco/msgpack v4.0.1+incompatible // indirect github.com/vmihailenco/msgpack v4.0.1+incompatible // indirect
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // 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/crypto v0.0.0-20181203042331-505ab145d0a9
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd // indirect golang.org/x/net v0.0.0-20180906233101-161cd47e91fd // indirect
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f // 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 google.golang.org/appengine v1.3.0 // indirect
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/natefinch/lumberjack.v2 v2.0.0

22
go.sum
View File

@ -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/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 h1:KjLSBawWQq6I0p9VRX8RtHIuttTYvUCGfMgNoBBFxYs=
github.com/Sereal/Sereal v0.0.0-20180905114147-563b78806e28/go.mod h1:D0JMgToj/WdxCgd30Kc1UcA9E+WdZoJqeVOuYW7iTBM= 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 h1:dczuIkyqwY2LrtXPz8ixMrU/OFgZp71kbKTHGrXYt/Q=
github.com/asdine/storm v2.1.2+incompatible/go.mod h1:RarYDc9hq1UPLImuiXK3BIWPJLdIygvV3PsInK0FbVQ= 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 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= 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 h1:tUf55Po0vzOendQ7NWytcdK0VuzQmfAgvGBUOQvN0WA=
github.com/daaku/go.zipexe v0.0.0-20150329023125-a5fe2436ffcb/go.mod h1:U0vRfAucUOohvdCxt5MWLF+TePIL0xbCkbKIiV8TQCE= 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= 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/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 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= 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 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 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= 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/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 h1:K2ugN3B7NOrATI7GfXRrwtbyg0OYVR9oNcm1XeTIyY4=
github.com/hacdias/fileutils v0.0.0-20171121222743-76b1c6ab9067/go.mod h1:lwnswzFVSy7B/k81M5rOLUU0fOBKHrDRIkPIBZd7PBo= 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 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 h1:PJPDf8OUfOK1bb/NeTKd4f1QXZItOX389VN3B6qC8ro= 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/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 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 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 h1:PEhRT94KBTY4E0KdCYmhvDGWjSFBxc68j2M6PMRix8U=
github.com/maruel/natural v0.0.0-20180416170133-dbcb3e2e8cf1/go.mod h1:wI697HNhDFM/vBruYM3ckbszQ2+DOIeH9qdBKMdf288= 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 h1:S1rFZ7umHtN6cG+6cusrfoXTMPqp6u/R89iKxBYJd4w=
github.com/mholt/archiver v3.1.0+incompatible/go.mod h1:Dh2dOXnSdiLxRiPoVfIr/fI1TwETms9B8CTWfeh7ROU= 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 h1:oNfejqftVesLoFxw53Gh17aBPNbTxQ9xJw1pn4IiAPk=
github.com/mholt/caddy v0.11.1/go.mod h1:Wb1PlT4DAYSqOEd03MsqkdkXnTxA8v9pKjdpxbqM1kY= 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 h1:r7vGuS5akxOnR4JQSkko62RJ1ReCMXxQRPtxsiFMBOs=
github.com/nwaples/rardecode v1.0.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/nwaples/rardecode v1.0.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= 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/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 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 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 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= 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 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 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 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 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 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok=
github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= 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 h1:RMF1enSPeKTlXrXdOcqjFUElywVZjjC6pqse21bKbEU=
github.com/vmihailenco/msgpack v4.0.1+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= 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 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= 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 h1:oY10fI923Q5pVCVt1GBTZMn8LHo5M+RCInFpeMnV4QI=
go.etcd.io/bbolt v1.3.0/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.0/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 h1:mKdxBk7AujPs8kU4m80U72y/zjbZ3UcXC7dClwKbUI0= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 h1:mKdxBk7AujPs8kU4m80U72y/zjbZ3UcXC7dClwKbUI0=