[WIP] add viper to manage envvars and cfg files
Former-commit-id: 99d241dc790629791b67b7b2ce20a10341a1c1e7 [formerly 08e8410bffdb50134a2d6ccbe853b25d4c4d3fc6] [formerly f32b18d9acb42ee1988c49b7980a16a606cee142 [formerly 1080bfde680d9d87271e63e6253450595e1f5c05]] Former-commit-id: 318c4f159697e896bcf824e274907c5c03046bf0 [formerly 82533ae817673dfab8d56533f15a9931c0c74c1e] Former-commit-id: ece42aa8e8c7480a5a21614b6ca397b71a01e1fa
This commit is contained in:
		
							parent
							
								
									2def76df83
								
							
						
					
					
						commit
						90b7f4aaf6
					
				| 
						 | 
					@ -8,5 +8,4 @@ EXPOSE 80
 | 
				
			||||||
 | 
					
 | 
				
			||||||
COPY filebrowser /filebrowser
 | 
					COPY filebrowser /filebrowser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ENTRYPOINT [ "/filebrowser", "--database", "/database.db" ]
 | 
					ENTRYPOINT [ "/filebrowser"]
 | 
				
			||||||
CMD [ "--scope /srv", "--port 80" ]
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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() {
 | 
				
			||||||
| 
						 | 
					@ -28,6 +29,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"))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										309
									
								
								cmd/root.go
								
								
								
								
							
							
						
						
									
										309
									
								
								cmd/root.go
								
								
								
								
							| 
						 | 
					@ -3,13 +3,13 @@ package cmd
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"crypto/rand"
 | 
						"crypto/rand"
 | 
				
			||||||
	"crypto/tls"
 | 
						"crypto/tls"
 | 
				
			||||||
	"errors"
 | 
					 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"log"
 | 
						"log"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/asdine/storm"
 | 
						"github.com/asdine/storm"
 | 
				
			||||||
	"github.com/filebrowser/filebrowser/v2/auth"
 | 
						"github.com/filebrowser/filebrowser/v2/auth"
 | 
				
			||||||
| 
						 | 
					@ -18,26 +18,13 @@ import (
 | 
				
			||||||
	"github.com/filebrowser/filebrowser/v2/users"
 | 
						"github.com/filebrowser/filebrowser/v2/users"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fbhttp "github.com/filebrowser/filebrowser/v2/http"
 | 
						fbhttp "github.com/filebrowser/filebrowser/v2/http"
 | 
				
			||||||
 | 
						homedir "github.com/mitchellh/go-homedir"
 | 
				
			||||||
	"github.com/spf13/cobra"
 | 
						"github.com/spf13/cobra"
 | 
				
			||||||
	"github.com/spf13/pflag"
 | 
						//	"github.com/spf13/pflag"
 | 
				
			||||||
 | 
						v "github.com/spf13/viper"
 | 
				
			||||||
	lumberjack "gopkg.in/natefinch/lumberjack.v2"
 | 
						lumberjack "gopkg.in/natefinch/lumberjack.v2"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					 | 
				
			||||||
	databasePath string
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func init() {
 | 
					 | 
				
			||||||
	rootCmd.PersistentFlags().StringVarP(&databasePath, "database", "d", "./filebrowser.db", "path to the database")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	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")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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",
 | 
				
			||||||
| 
						 | 
					@ -56,17 +43,211 @@ 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
 | 
					values won't be persisted to the database. To persist configuration to the database
 | 
				
			||||||
use the command 'filebrowser config set'.`,
 | 
					use the command 'filebrowser config set'.`,
 | 
				
			||||||
	Run: func(cmd *cobra.Command, args []string) {
 | 
						Run: func(cmd *cobra.Command, args []string) {
 | 
				
			||||||
		if _, err := os.Stat(databasePath); os.IsNotExist(err) {
 | 
					 | 
				
			||||||
			quickSetup(cmd)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		db := getDB()
 | 
							db := getDB()
 | 
				
			||||||
		defer db.Close()
 | 
							defer db.Close()
 | 
				
			||||||
		st := getStorage(db)
 | 
							st := getStorage(db)
 | 
				
			||||||
		startServer(cmd, st)
 | 
							startServer(st)
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						cfgFile string
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// POSSIBLE WORKAROUND TO IDENTIFY WHEN DEFAULT VALUES ARE BEING USED
 | 
				
			||||||
 | 
					var defaults = struct {
 | 
				
			||||||
 | 
						database string
 | 
				
			||||||
 | 
						address  string
 | 
				
			||||||
 | 
						log      string
 | 
				
			||||||
 | 
						port     int
 | 
				
			||||||
 | 
						scope    string
 | 
				
			||||||
 | 
						admin    string
 | 
				
			||||||
 | 
					}{
 | 
				
			||||||
 | 
						"./filebrowser.db",
 | 
				
			||||||
 | 
						"127.0.0.1",
 | 
				
			||||||
 | 
						"stderr",
 | 
				
			||||||
 | 
						80,
 | 
				
			||||||
 | 
						"/srv",
 | 
				
			||||||
 | 
						"admin",
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						cobra.OnInitialize(initConfig)
 | 
				
			||||||
 | 
						//rootCmd.SetVersionTemplate("File Browser {{printf \"version %s\" .Version}}\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						f := rootCmd.Flags()
 | 
				
			||||||
 | 
						pf := rootCmd.PersistentFlags()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pf.StringVarP(&cfgFile, "config", "c", "", "config file (defaults are './.filebrowser[ext]', '$HOME/.filebrowser[ext]' or '/etc/filebrowser/.filebrowser[ext]')")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vaddP(pf, "database", "d", "./filebrowser.db", "path to the database")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vaddP(f, "address", "a", defaults.address, "address to listen on")
 | 
				
			||||||
 | 
						vaddP(f, "log", "l", defaults.log, "log output")
 | 
				
			||||||
 | 
						vaddP(f, "port", "p", defaults.port, "port to listen on")
 | 
				
			||||||
 | 
						vaddP(f, "cert", "t", "", "tls certificate (default comes from database)")
 | 
				
			||||||
 | 
						vaddP(f, "key", "k", "", "tls key (default comes from database)")
 | 
				
			||||||
 | 
						vaddP(f, "scope", "s", defaults.scope, "scope for users")
 | 
				
			||||||
 | 
						vaddP(f, "force", "f", false, "overwrite DB config with runtime params")
 | 
				
			||||||
 | 
						vaddP(f, "admin", "f", defaults.admin, "first username")
 | 
				
			||||||
 | 
						vaddP(f, "passwd", "f", "", "first username password hash")
 | 
				
			||||||
 | 
						vaddP(f, "baseurl", "b", "", "base URL")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Bind the full flag sets to the configuration
 | 
				
			||||||
 | 
						if err := v.BindPFlags(f); err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := v.BindPFlags(pf); err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// initConfig reads in config file and ENV variables if set.
 | 
				
			||||||
 | 
					func initConfig() {
 | 
				
			||||||
 | 
						if cfgFile == "" {
 | 
				
			||||||
 | 
							// Find home directory.
 | 
				
			||||||
 | 
							home, err := homedir.Dir()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								panic(err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							v.AddConfigPath(".")
 | 
				
			||||||
 | 
							v.AddConfigPath(home)
 | 
				
			||||||
 | 
							v.AddConfigPath("/etc/filebrowser/")
 | 
				
			||||||
 | 
							v.SetConfigName(".filebrowser")
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							// Use config file from the flag.
 | 
				
			||||||
 | 
							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)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							log.Println("No config file provided")
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							log.Println("Using config file:", v.ConfigFileUsed())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						log.Println("FORCE:", v.GetBool("force"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						   if DB exists
 | 
				
			||||||
 | 
						     if force false
 | 
				
			||||||
 | 
						       database has highest priority, if undefined in DB use config params
 | 
				
			||||||
 | 
						     else
 | 
				
			||||||
 | 
						       config params overwrite existing and non-existing params in DB
 | 
				
			||||||
 | 
						   else
 | 
				
			||||||
 | 
						     (quick)Setup with provided config params
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						   DISPLAY WARNINGS WHEN DEFAULT VALUES ARE USED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						     This allows to know if a CLI flag was provided:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						       log.Println(rootCmd.Flags().Changed("database"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						     However, that is not enough in order to know if a value came from a config file or from envvars.
 | 
				
			||||||
 | 
						     This should allow so. But it seems not to work as expected (see spf13/viper#323):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						       log.Println(v.IsSet("database"))
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if _, err := os.Stat(v.GetString("database")); os.IsNotExist(err) {
 | 
				
			||||||
 | 
							quickSetup()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					func serverVisitAndReplace(s *settings.Settings) {
 | 
				
			||||||
 | 
						rootCmd.Flags().Visit(func(flag *pflag.Flag) {
 | 
				
			||||||
 | 
							switch flag.Name {
 | 
				
			||||||
 | 
							case "log":
 | 
				
			||||||
 | 
								s.Log = v.GetString(flag.Name)
 | 
				
			||||||
 | 
							case "address":
 | 
				
			||||||
 | 
								s.Server.Address = v.GetString(flag.Name)
 | 
				
			||||||
 | 
							case "port":
 | 
				
			||||||
 | 
								s.Server.Port = v.GetInt(flag.Name)
 | 
				
			||||||
 | 
							case "cert":
 | 
				
			||||||
 | 
								s.Server.TLSCert = v.GetString(flag.Name)
 | 
				
			||||||
 | 
							case "key":
 | 
				
			||||||
 | 
								s.Server.TLSKey = v.GetString(flag.Name)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func quickSetup() {
 | 
				
			||||||
 | 
						scope := v.GetString("scope")
 | 
				
			||||||
 | 
						if scope == defaults.scope {
 | 
				
			||||||
 | 
							log.Println("[WARN] Using default value '/srv' as param 'scope'")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						db, err := storm.Open(v.GetString("database"))
 | 
				
			||||||
 | 
						checkErr(err)
 | 
				
			||||||
 | 
						defer db.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						set := &settings.Settings{
 | 
				
			||||||
 | 
							Key:        generateRandomBytes(64), // 256 bit
 | 
				
			||||||
 | 
							BaseURL:    v.GetString("baseurl"),
 | 
				
			||||||
 | 
							Log:        v.GetString("log"),
 | 
				
			||||||
 | 
							Signup:     false,
 | 
				
			||||||
 | 
							AuthMethod: auth.MethodJSONAuth,
 | 
				
			||||||
 | 
							Server: settings.Server{
 | 
				
			||||||
 | 
								Port:    v.GetInt("port"),
 | 
				
			||||||
 | 
								Address: v.GetString("address"),
 | 
				
			||||||
 | 
								TLSCert: v.GetString("cert"),
 | 
				
			||||||
 | 
								TLSKey:  v.GetString("key"),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							Defaults: settings.UserDefaults{
 | 
				
			||||||
 | 
								Scope:  scope,
 | 
				
			||||||
 | 
								Locale: "en",
 | 
				
			||||||
 | 
								Perm: users.Permissions{
 | 
				
			||||||
 | 
									Admin:    false,
 | 
				
			||||||
 | 
									Execute:  true,
 | 
				
			||||||
 | 
									Create:   true,
 | 
				
			||||||
 | 
									Rename:   true,
 | 
				
			||||||
 | 
									Modify:   true,
 | 
				
			||||||
 | 
									Delete:   true,
 | 
				
			||||||
 | 
									Share:    true,
 | 
				
			||||||
 | 
									Download: true,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//	serverVisitAndReplace(set)
 | 
				
			||||||
 | 
						st := getStorage(db)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = st.Settings.Save(set)
 | 
				
			||||||
 | 
						checkErr(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = st.Auth.Save(&auth.JSONAuth{})
 | 
				
			||||||
 | 
						checkErr(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						password := v.GetString("password")
 | 
				
			||||||
 | 
						if password == "" {
 | 
				
			||||||
 | 
							password, err = users.HashPwd("admin")
 | 
				
			||||||
 | 
							checkErr(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						user := &users.User{
 | 
				
			||||||
 | 
							Username:     v.GetString("admin"),
 | 
				
			||||||
 | 
							Password:     password,
 | 
				
			||||||
 | 
							LockPassword: false,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						set.Defaults.Apply(user)
 | 
				
			||||||
 | 
						user.Perm.Admin = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = st.Users.Save(user)
 | 
				
			||||||
 | 
						checkErr(err)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func setupLogger(s *settings.Settings) {
 | 
					func setupLogger(s *settings.Settings) {
 | 
				
			||||||
	switch s.Log {
 | 
						switch s.Log {
 | 
				
			||||||
	case "stdout":
 | 
						case "stdout":
 | 
				
			||||||
| 
						 | 
					@ -85,91 +266,11 @@ func setupLogger(s *settings.Settings) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func serverVisitAndReplace(cmd *cobra.Command, s *settings.Settings) {
 | 
					func startServer(st *storage.Storage) {
 | 
				
			||||||
	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 == "" {
 | 
					 | 
				
			||||||
		panic(errors.New("scope flag must be set for quick setup"))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	db, err := storm.Open(databasePath)
 | 
					 | 
				
			||||||
	checkErr(err)
 | 
					 | 
				
			||||||
	defer db.Close()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	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",
 | 
					 | 
				
			||||||
			Perm: users.Permissions{
 | 
					 | 
				
			||||||
				Admin:    false,
 | 
					 | 
				
			||||||
				Execute:  true,
 | 
					 | 
				
			||||||
				Create:   true,
 | 
					 | 
				
			||||||
				Rename:   true,
 | 
					 | 
				
			||||||
				Modify:   true,
 | 
					 | 
				
			||||||
				Delete:   true,
 | 
					 | 
				
			||||||
				Share:    true,
 | 
					 | 
				
			||||||
				Download: true,
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	serverVisitAndReplace(cmd, set)
 | 
					 | 
				
			||||||
	st := getStorage(db)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = st.Settings.Save(set)
 | 
					 | 
				
			||||||
	checkErr(err)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = st.Auth.Save(&auth.JSONAuth{})
 | 
					 | 
				
			||||||
	checkErr(err)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	password, err := users.HashPwd("admin")
 | 
					 | 
				
			||||||
	checkErr(err)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	user := &users.User{
 | 
					 | 
				
			||||||
		Username:     "admin",
 | 
					 | 
				
			||||||
		Password:     password,
 | 
					 | 
				
			||||||
		LockPassword: false,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	set.Defaults.Apply(user)
 | 
					 | 
				
			||||||
	user.Perm.Admin = true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = st.Users.Save(user)
 | 
					 | 
				
			||||||
	checkErr(err)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func startServer(cmd *cobra.Command, st *storage.Storage) {
 | 
					 | 
				
			||||||
	settings, err := st.Settings.Get()
 | 
						settings, err := st.Settings.Get()
 | 
				
			||||||
	checkErr(err)
 | 
						checkErr(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	serverVisitAndReplace(cmd, settings)
 | 
						//	serverVisitAndReplace(settings)
 | 
				
			||||||
	setupLogger(settings)
 | 
						setupLogger(settings)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	handler, err := fbhttp.NewHandler(st)
 | 
						handler, err := fbhttp.NewHandler(st)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										27
									
								
								cmd/utils.go
								
								
								
								
							
							
						
						
									
										27
									
								
								cmd/utils.go
								
								
								
								
							| 
						 | 
					@ -8,8 +8,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)
 | 
				
			||||||
| 
						 | 
					@ -41,6 +67,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."))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										6
									
								
								go.mod
								
								
								
								
							
							
						
						
									
										6
									
								
								go.mod
								
								
								
								
							| 
						 | 
					@ -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
								
								
								
								
							
							
						
						
									
										22
									
								
								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/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=
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue