commit
						143dcec6f7
					
				| 
						 | 
				
			
			@ -7,7 +7,5 @@ VOLUME /srv
 | 
			
		|||
EXPOSE 80
 | 
			
		||||
 | 
			
		||||
COPY filebrowser /filebrowser
 | 
			
		||||
COPY docker-entrypoint.sh /entrypoint.sh
 | 
			
		||||
 | 
			
		||||
ENTRYPOINT [ "/entrypoint.sh" ]
 | 
			
		||||
CMD [ "run" ]
 | 
			
		||||
ENTRYPOINT [ "/filebrowser"]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 <event> <command>",
 | 
			
		||||
	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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 <event> <index> [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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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, " "))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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":
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										132
									
								
								cmd/root.go
								
								
								
								
							
							
						
						
									
										132
									
								
								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())
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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> [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)
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										12
									
								
								cmd/rules.go
								
								
								
								
							
							
						
						
									
										12
									
								
								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)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 <path|expression>",
 | 
			
		||||
	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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										14
									
								
								cmd/users.go
								
								
								
								
							
							
						
						
									
										14
									
								
								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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 <username> <password>",
 | 
			
		||||
	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"),
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -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 <id|username>",
 | 
			
		||||
	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)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 <id|username>",
 | 
			
		||||
	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 != "" {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 <id|username>",
 | 
			
		||||
	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 != "" {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										33
									
								
								cmd/utils.go
								
								
								
								
							
							
						
						
									
										33
									
								
								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."))
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
								
								
								
								
							
							
						
						
									
										6
									
								
								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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										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/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=
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue