commit
b4b578b90f
@ -3,7 +3,7 @@ project_name: filebrowser
|
|||||||
build:
|
build:
|
||||||
env:
|
env:
|
||||||
- CGO_ENABLED=0
|
- CGO_ENABLED=0
|
||||||
main: cli/main.go
|
main: main.go
|
||||||
binary: filebrowser
|
binary: filebrowser
|
||||||
goos:
|
goos:
|
||||||
- darwin
|
- darwin
|
||||||
@ -50,8 +50,9 @@ dockers:
|
|||||||
goos: linux
|
goos: linux
|
||||||
goarch: amd64
|
goarch: amd64
|
||||||
goarm: ''
|
goarm: ''
|
||||||
image: filebrowser/filebrowser
|
image_templates:
|
||||||
|
- "filebrowser/filebrowser:latest"
|
||||||
|
- "filebrowser/filebrowser:{{ .Tag }}"
|
||||||
skip_push: true
|
skip_push: true
|
||||||
tag_templates:
|
extra_files:
|
||||||
- "{{ .Tag }}"
|
- .docker.json
|
||||||
- latest
|
|
||||||
|
|||||||
@ -32,7 +32,7 @@ jobs:
|
|||||||
repo: filebrowser/filebrowser
|
repo: filebrowser/filebrowser
|
||||||
branch: master
|
branch: master
|
||||||
- stage: release
|
- stage: release
|
||||||
script: ./wizard.sh -r
|
script: ./wizard.sh -r "$TRAVIS_TAG"
|
||||||
if: tag IS present
|
if: tag IS present
|
||||||
deploy:
|
deploy:
|
||||||
provider: releases
|
provider: releases
|
||||||
|
|||||||
@ -2,11 +2,10 @@ FROM scratch
|
|||||||
|
|
||||||
COPY --from=filebrowser/dev /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
COPY --from=filebrowser/dev /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
||||||
|
|
||||||
VOLUME /tmp
|
|
||||||
VOLUME /srv
|
VOLUME /srv
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
COPY .filebrowser.docker.json /.filebrowser.json
|
COPY .docker.json /.filebrowser.json
|
||||||
COPY filebrowser /filebrowser
|
COPY filebrowser /filebrowser
|
||||||
|
|
||||||
ENTRYPOINT [ "/filebrowser" ]
|
ENTRYPOINT [ "/filebrowser" ]
|
||||||
|
|||||||
@ -15,5 +15,5 @@ type NoAuth struct{}
|
|||||||
|
|
||||||
// Auth uses authenticates user 1.
|
// Auth uses authenticates user 1.
|
||||||
func (a NoAuth) Auth(r *http.Request, sto *users.Storage, root string) (*users.User, error) {
|
func (a NoAuth) Auth(r *http.Request, sto *users.Storage, root string) (*users.User, error) {
|
||||||
return sto.Get(root, 1)
|
return sto.Get(root, uint(1))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,7 @@ func init() {
|
|||||||
|
|
||||||
var cmdsCmd = &cobra.Command{
|
var cmdsCmd = &cobra.Command{
|
||||||
Use: "cmds",
|
Use: "cmds",
|
||||||
|
Version: rootCmd.Version,
|
||||||
Short: "Command runner management utility",
|
Short: "Command runner management utility",
|
||||||
Long: `Command runner management utility.`,
|
Long: `Command runner management utility.`,
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
|
|||||||
@ -13,7 +13,15 @@ func init() {
|
|||||||
var cmdsRmCmd = &cobra.Command{
|
var cmdsRmCmd = &cobra.Command{
|
||||||
Use: "rm <event> <index> [index_end]",
|
Use: "rm <event> <index> [index_end]",
|
||||||
Short: "Removes a command from an event hooker",
|
Short: "Removes a command from an event hooker",
|
||||||
Long: `Removes a command from an event hooker.`,
|
Long: `Removes a command from an event hooker. The provided index
|
||||||
|
is the same that's printed when you run 'cmds ls'. Note
|
||||||
|
that after each removal/addition, the index of the
|
||||||
|
commands change. So be careful when removing them after each
|
||||||
|
other.
|
||||||
|
|
||||||
|
You can also specify an optional parameter (index_end) so
|
||||||
|
you can remove all commands from 'index' to 'index_end',
|
||||||
|
including 'index_end'.`,
|
||||||
Args: func(cmd *cobra.Command, args []string) error {
|
Args: func(cmd *cobra.Command, args []string) error {
|
||||||
if err := cobra.RangeArgs(2, 3)(cmd, args); err != nil {
|
if err := cobra.RangeArgs(2, 3)(cmd, args); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@ -21,6 +21,7 @@ func init() {
|
|||||||
|
|
||||||
var configCmd = &cobra.Command{
|
var configCmd = &cobra.Command{
|
||||||
Use: "config",
|
Use: "config",
|
||||||
|
Version: rootCmd.Version,
|
||||||
Short: "Configuration management utility",
|
Short: "Configuration management utility",
|
||||||
Long: `Configuration management utility.`,
|
Long: `Configuration management utility.`,
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
|
|||||||
@ -9,8 +9,11 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var configExportCmd = &cobra.Command{
|
var configExportCmd = &cobra.Command{
|
||||||
Use: "export <filename>",
|
Use: "export <path>",
|
||||||
Short: "Export the configuration to a file.",
|
Short: "Export the configuration to a file",
|
||||||
|
Long: `Export the configuration to a file. The path must be for a
|
||||||
|
json or yaml file. This exported configuration can be changed,
|
||||||
|
and imported again with 'config import' command.`,
|
||||||
Args: jsonYamlArg,
|
Args: jsonYamlArg,
|
||||||
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||||
settings, err := d.store.Settings.Get()
|
settings, err := d.store.Settings.Get()
|
||||||
|
|||||||
@ -22,12 +22,16 @@ type settingsFile struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var configImportCmd = &cobra.Command{
|
var configImportCmd = &cobra.Command{
|
||||||
Use: "import <filename>",
|
Use: "import <path>",
|
||||||
Short: `Import a configuration file. This will replace all the existing
|
Short: "Import a configuration file",
|
||||||
|
Long: `Import a configuration file. This will replace all the existing
|
||||||
configuration. Can be used with or without unexisting databases.
|
configuration. Can be used with or without unexisting databases.
|
||||||
|
|
||||||
If used with a nonexisting database, a key will be generated
|
If used with a nonexisting database, a key will be generated
|
||||||
automatically. Otherwise the key will be kept the same as in the
|
automatically. Otherwise the key will be kept the same as in the
|
||||||
database.`,
|
database.
|
||||||
|
|
||||||
|
The path must be for a json or yaml file.`,
|
||||||
Args: jsonYamlArg,
|
Args: jsonYamlArg,
|
||||||
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||||
var key []byte
|
var key []byte
|
||||||
|
|||||||
@ -18,7 +18,7 @@ var configInitCmd = &cobra.Command{
|
|||||||
Short: "Initialize a new database",
|
Short: "Initialize a new database",
|
||||||
Long: `Initialize a new database to use with File Browser. All of
|
Long: `Initialize a new database to use with File Browser. All of
|
||||||
this options can be changed in the future with the command
|
this options can be changed in the future with the command
|
||||||
"filebrowser config set". The user related flags apply
|
'filebrowser config set'. The user related flags apply
|
||||||
to the defaults when creating new users and you don't
|
to the defaults when creating new users and you don't
|
||||||
override the options.`,
|
override the options.`,
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
|
|||||||
@ -17,7 +17,7 @@ var configSetCmd = &cobra.Command{
|
|||||||
Use: "set",
|
Use: "set",
|
||||||
Short: "Updates the configuration",
|
Short: "Updates the configuration",
|
||||||
Long: `Updates the configuration. Set the flags for the options
|
Long: `Updates the configuration. Set the flags for the options
|
||||||
you want to change.`,
|
you want to change. Other options will remain unchanged.`,
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||||
flags := cmd.Flags()
|
flags := cmd.Flags()
|
||||||
|
|||||||
@ -9,8 +9,8 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/spf13/pflag"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
@ -13,6 +13,7 @@ func init() {
|
|||||||
|
|
||||||
var hashCmd = &cobra.Command{
|
var hashCmd = &cobra.Command{
|
||||||
Use: "hash <password>",
|
Use: "hash <password>",
|
||||||
|
Version: rootCmd.Version,
|
||||||
Short: "Hashes a password",
|
Short: "Hashes a password",
|
||||||
Long: `Hashes a password using bcrypt algorithm.`,
|
Long: `Hashes a password using bcrypt algorithm.`,
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
|
|||||||
157
cmd/root.go
157
cmd/root.go
@ -2,7 +2,6 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"errors"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
@ -16,7 +15,8 @@ import (
|
|||||||
"github.com/filebrowser/filebrowser/v2/settings"
|
"github.com/filebrowser/filebrowser/v2/settings"
|
||||||
"github.com/filebrowser/filebrowser/v2/storage"
|
"github.com/filebrowser/filebrowser/v2/storage"
|
||||||
"github.com/filebrowser/filebrowser/v2/users"
|
"github.com/filebrowser/filebrowser/v2/users"
|
||||||
"github.com/mitchellh/go-homedir"
|
"github.com/filebrowser/filebrowser/v2/version"
|
||||||
|
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"
|
v "github.com/spf13/viper"
|
||||||
@ -29,11 +29,15 @@ var (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
cobra.OnInitialize(initConfig)
|
cobra.OnInitialize(initConfig)
|
||||||
|
|
||||||
|
rootCmd.SetVersionTemplate("File Browser version {{printf \"%s\" .Version}}\n")
|
||||||
|
|
||||||
flags := rootCmd.Flags()
|
flags := rootCmd.Flags()
|
||||||
persistent := rootCmd.PersistentFlags()
|
persistent := rootCmd.PersistentFlags()
|
||||||
|
|
||||||
persistent.StringVarP(&cfgFile, "config", "c", "", "config file path")
|
persistent.StringVarP(&cfgFile, "config", "c", "", "config file path")
|
||||||
persistent.StringP("database", "d", "./filebrowser.db", "database path")
|
persistent.StringP("database", "d", "./filebrowser.db", "database path")
|
||||||
|
flags.Bool("noauth", false, "use the noauth auther when using quick setup")
|
||||||
flags.String("username", "admin", "username for the first user when using quick config")
|
flags.String("username", "admin", "username for the first user when using quick config")
|
||||||
flags.String("password", "", "hashed password for the first user when using quick config (default \"admin\")")
|
flags.String("password", "", "hashed password for the first user when using quick config (default \"admin\")")
|
||||||
|
|
||||||
@ -50,44 +54,9 @@ func addServerFlags(flags *pflag.FlagSet) {
|
|||||||
flags.StringP("baseurl", "b", "", "base url")
|
flags.StringP("baseurl", "b", "", "base url")
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: we could simply bind the flags to viper and use IsSet.
|
|
||||||
// Although there is a bug on Viper that always returns true on IsSet
|
|
||||||
// if a flag is binded. Our alternative way is to manually check
|
|
||||||
// the flag and then the value from env/config/gotten by viper.
|
|
||||||
// https://github.com/spf13/viper/pull/331
|
|
||||||
func getStringViperFlag(flags *pflag.FlagSet, key string) (string, bool) {
|
|
||||||
value := ""
|
|
||||||
set := false
|
|
||||||
|
|
||||||
// If set on Flags, use it.
|
|
||||||
flags.Visit(func(flag *pflag.Flag) {
|
|
||||||
if flag.Name == key {
|
|
||||||
set = true
|
|
||||||
value, _ = flags.GetString(key)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if set {
|
|
||||||
return value, set
|
|
||||||
}
|
|
||||||
|
|
||||||
// If set through viper (env, config), return it.
|
|
||||||
if v.IsSet(key) {
|
|
||||||
return v.GetString(key), true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise use default value on flags.
|
|
||||||
value, _ = flags.GetString(key)
|
|
||||||
return value, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func mustGetStringViperFlag(flags *pflag.FlagSet, key string) string {
|
|
||||||
val, _ := getStringViperFlag(flags, key)
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
|
|
||||||
var rootCmd = &cobra.Command{
|
var rootCmd = &cobra.Command{
|
||||||
Use: "filebrowser",
|
Use: "filebrowser",
|
||||||
|
Version: version.Version,
|
||||||
Short: "A stylish web-based file browser",
|
Short: "A stylish web-based file browser",
|
||||||
Long: `File Browser CLI lets you create the database to use with File Browser,
|
Long: `File Browser CLI lets you create the database to use with File Browser,
|
||||||
manage your users and all the configurations without acessing the
|
manage your users and all the configurations without acessing the
|
||||||
@ -111,46 +80,50 @@ If you don't set "config", it will look for a configuration file called
|
|||||||
|
|
||||||
The precedence of the configuration values are as follows:
|
The precedence of the configuration values are as follows:
|
||||||
|
|
||||||
- flag
|
- flags
|
||||||
- environment variable
|
- environment variables
|
||||||
- configuration file
|
- configuration file
|
||||||
|
- database values
|
||||||
- defaults
|
- defaults
|
||||||
|
|
||||||
The environment variables are prefixed by "FB_" followed by the option
|
The environment variables are prefixed by "FB_" followed by the option
|
||||||
name in caps. So to set "database" via an env variable, you should
|
name in caps. So to set "database" via an env variable, you should
|
||||||
set FB_DATABASE equals to the path.
|
set FB_DATABASE.
|
||||||
|
|
||||||
Also, if the database path doesn't exist, File Browser will enter into
|
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
|
the quick setup mode and a new database will be bootstraped and a new
|
||||||
user created with the credentials from options "username" and "password".`,
|
user created with the credentials from options "username" and "password".`,
|
||||||
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||||
|
log.Println(cfgFile)
|
||||||
|
|
||||||
if !d.hadDB {
|
if !d.hadDB {
|
||||||
quickSetup(cmd.Flags(), d)
|
quickSetup(cmd.Flags(), d)
|
||||||
}
|
}
|
||||||
|
|
||||||
server := getServerWithViper(cmd.Flags(), d.store)
|
server := getRunParams(cmd.Flags(), d.store)
|
||||||
setupLog(server.Log)
|
setupLog(server.Log)
|
||||||
|
|
||||||
root, err := filepath.Abs(server.Root)
|
root, err := filepath.Abs(server.Root)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
server.Root = root
|
server.Root = root
|
||||||
|
|
||||||
handler, err := fbhttp.NewHandler(d.store, server)
|
adr := server.Address + ":" + server.Port
|
||||||
checkErr(err)
|
|
||||||
|
|
||||||
var listener net.Listener
|
var listener net.Listener
|
||||||
|
|
||||||
if server.TLSKey != "" && server.TLSCert != "" {
|
if server.TLSKey != "" && server.TLSCert != "" {
|
||||||
cer, err := tls.LoadX509KeyPair(server.TLSCert, server.TLSKey)
|
cer, err := tls.LoadX509KeyPair(server.TLSCert, server.TLSKey)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
config := &tls.Config{Certificates: []tls.Certificate{cer}}
|
listener, err = tls.Listen("tcp", adr, &tls.Config{Certificates: []tls.Certificate{cer}})
|
||||||
listener, err = tls.Listen("tcp", server.Address+":"+server.Port, config)
|
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
} else {
|
} else {
|
||||||
listener, err = net.Listen("tcp", server.Address+":"+server.Port)
|
listener, err = net.Listen("tcp", adr)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handler, err := fbhttp.NewHandler(d.store, server)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
log.Println("Listening on", listener.Addr().String())
|
log.Println("Listening on", listener.Addr().String())
|
||||||
if err := http.Serve(listener, handler); err != nil {
|
if err := http.Serve(listener, handler); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
@ -158,41 +131,70 @@ user created with the credentials from options "username" and "password".`,
|
|||||||
}, pythonConfig{allowNoDB: true}),
|
}, pythonConfig{allowNoDB: true}),
|
||||||
}
|
}
|
||||||
|
|
||||||
func getServerWithViper(flags *pflag.FlagSet, st *storage.Storage) *settings.Server {
|
func getRunParams(flags *pflag.FlagSet, st *storage.Storage) *settings.Server {
|
||||||
server, err := st.Settings.GetServer()
|
server, err := st.Settings.GetServer()
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|
||||||
if val, set := getStringViperFlag(flags, "root"); set {
|
if val, set := getParamB(flags, "root"); set {
|
||||||
server.Root = val
|
server.Root = val
|
||||||
}
|
}
|
||||||
|
|
||||||
if val, set := getStringViperFlag(flags, "baseurl"); set {
|
if val, set := getParamB(flags, "baseurl"); set {
|
||||||
server.BaseURL = val
|
server.BaseURL = val
|
||||||
}
|
}
|
||||||
|
|
||||||
if val, set := getStringViperFlag(flags, "address"); set {
|
if val, set := getParamB(flags, "address"); set {
|
||||||
server.Address = val
|
server.Address = val
|
||||||
}
|
}
|
||||||
|
|
||||||
if val, set := getStringViperFlag(flags, "port"); set {
|
if val, set := getParamB(flags, "port"); set {
|
||||||
server.Port = val
|
server.Port = val
|
||||||
}
|
}
|
||||||
|
|
||||||
if val, set := getStringViperFlag(flags, "log"); set {
|
if val, set := getParamB(flags, "log"); set {
|
||||||
server.Log = val
|
server.Log = val
|
||||||
}
|
}
|
||||||
|
|
||||||
if val, set := getStringViperFlag(flags, "key"); set {
|
if val, set := getParamB(flags, "key"); set {
|
||||||
server.TLSKey = val
|
server.TLSKey = val
|
||||||
}
|
}
|
||||||
|
|
||||||
if val, set := getStringViperFlag(flags, "cert"); set {
|
if val, set := getParamB(flags, "cert"); set {
|
||||||
server.TLSCert = val
|
server.TLSCert = val
|
||||||
}
|
}
|
||||||
|
|
||||||
return server
|
return server
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getParamB returns a parameter as a string and a boolean to tell if it is different from the default
|
||||||
|
//
|
||||||
|
// NOTE: we could simply bind the flags to viper and use IsSet.
|
||||||
|
// Although there is a bug on Viper that always returns true on IsSet
|
||||||
|
// if a flag is binded. Our alternative way is to manually check
|
||||||
|
// the flag and then the value from env/config/gotten by viper.
|
||||||
|
// https://github.com/spf13/viper/pull/331
|
||||||
|
func getParamB(flags *pflag.FlagSet, key string) (string, bool) {
|
||||||
|
value, _ := flags.GetString(key)
|
||||||
|
|
||||||
|
// If set on Flags, use it.
|
||||||
|
if flags.Changed(key) {
|
||||||
|
return value, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// If set through viper (env, config), return it.
|
||||||
|
if v.IsSet(key) {
|
||||||
|
return v.GetString(key), true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise use default value on flags.
|
||||||
|
return value, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func getParam(flags *pflag.FlagSet, key string) string {
|
||||||
|
val, _ := getParamB(flags, key)
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
func setupLog(logMethod string) {
|
func setupLog(logMethod string) {
|
||||||
switch logMethod {
|
switch logMethod {
|
||||||
case "stdout":
|
case "stdout":
|
||||||
@ -209,14 +211,12 @@ func setupLog(logMethod string) {
|
|||||||
MaxBackups: 10,
|
MaxBackups: 10,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func quickSetup(flags *pflag.FlagSet, d pythonData) {
|
func quickSetup(flags *pflag.FlagSet, d pythonData) {
|
||||||
set := &settings.Settings{
|
set := &settings.Settings{
|
||||||
Key: generateRandomBytes(64), // 256 bit
|
Key: generateRandomBytes(64), // 256 bit
|
||||||
Signup: false,
|
Signup: false,
|
||||||
AuthMethod: auth.MethodJSONAuth,
|
|
||||||
Defaults: settings.UserDefaults{
|
Defaults: settings.UserDefaults{
|
||||||
Scope: ".",
|
Scope: ".",
|
||||||
Locale: "en",
|
Locale: "en",
|
||||||
@ -233,27 +233,34 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
ser := &settings.Server{
|
var err error
|
||||||
BaseURL: mustGetStringViperFlag(flags, "baseurl"),
|
if _, noauth := getParamB(flags, "noauth"); noauth {
|
||||||
Port: mustGetStringViperFlag(flags, "port"),
|
set.AuthMethod = auth.MethodNoAuth
|
||||||
Log: mustGetStringViperFlag(flags, "log"),
|
err = d.store.Auth.Save(&auth.NoAuth{})
|
||||||
TLSKey: mustGetStringViperFlag(flags, "key"),
|
} else {
|
||||||
TLSCert: mustGetStringViperFlag(flags, "cert"),
|
set.AuthMethod = auth.MethodJSONAuth
|
||||||
Address: mustGetStringViperFlag(flags, "address"),
|
err = d.store.Auth.Save(&auth.JSONAuth{})
|
||||||
Root: mustGetStringViperFlag(flags, "root"),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err := d.store.Settings.Save(set)
|
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
err = d.store.Settings.Save(set)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
ser := &settings.Server{
|
||||||
|
BaseURL: getParam(flags, "baseurl"),
|
||||||
|
Port: getParam(flags, "port"),
|
||||||
|
Log: getParam(flags, "log"),
|
||||||
|
TLSKey: getParam(flags, "key"),
|
||||||
|
TLSCert: getParam(flags, "cert"),
|
||||||
|
Address: getParam(flags, "address"),
|
||||||
|
Root: getParam(flags, "root"),
|
||||||
|
}
|
||||||
|
|
||||||
err = d.store.Settings.SaveServer(ser)
|
err = d.store.Settings.SaveServer(ser)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|
||||||
err = d.store.Auth.Save(&auth.JSONAuth{})
|
username := getParam(flags, "username")
|
||||||
checkErr(err)
|
password := getParam(flags, "password")
|
||||||
|
|
||||||
username := mustGetStringViperFlag(flags, "username")
|
|
||||||
password := mustGetStringViperFlag(flags, "password")
|
|
||||||
|
|
||||||
if password == "" {
|
if password == "" {
|
||||||
password, err = users.HashPwd("admin")
|
password, err = users.HashPwd("admin")
|
||||||
@ -261,7 +268,7 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if username == "" || password == "" {
|
if username == "" || password == "" {
|
||||||
checkErr(errors.New("username and password cannot be empty during quick setup"))
|
log.Fatal("username and password cannot be empty during quick setup")
|
||||||
}
|
}
|
||||||
|
|
||||||
user := &users.User{
|
user := &users.User{
|
||||||
@ -297,7 +304,9 @@ func initConfig() {
|
|||||||
if _, ok := err.(v.ConfigParseError); ok {
|
if _, ok := err.(v.ConfigParseError); ok {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
// TODO: log.Println("No config file provided")
|
cfgFile = "No config file used"
|
||||||
|
} else {
|
||||||
|
cfgFile = "Using config file: " + v.ConfigFileUsed()
|
||||||
}
|
}
|
||||||
// else TODO: log.Println("Using config file:", v.ConfigFileUsed())
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,15 @@ func init() {
|
|||||||
var rulesRmCommand = &cobra.Command{
|
var rulesRmCommand = &cobra.Command{
|
||||||
Use: "rm <index> [index_end]",
|
Use: "rm <index> [index_end]",
|
||||||
Short: "Remove a global rule or user rule",
|
Short: "Remove a global rule or user rule",
|
||||||
Long: `Remove a global rule or user rule.`,
|
Long: `Remove a global rule or user rule. The provided index
|
||||||
|
is the same that's printed when you run 'rules ls'. Note
|
||||||
|
that after each removal/addition, the index of the
|
||||||
|
commands change. So be careful when removing them after each
|
||||||
|
other.
|
||||||
|
|
||||||
|
You can also specify an optional parameter (index_end) so
|
||||||
|
you can remove all commands from 'index' to 'index_end',
|
||||||
|
including 'index_end'.`,
|
||||||
Args: func(cmd *cobra.Command, args []string) error {
|
Args: func(cmd *cobra.Command, args []string) error {
|
||||||
if err := cobra.RangeArgs(1, 2)(cmd, args); err != nil {
|
if err := cobra.RangeArgs(1, 2)(cmd, args); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@ -19,6 +19,7 @@ func init() {
|
|||||||
|
|
||||||
var rulesCmd = &cobra.Command{
|
var rulesCmd = &cobra.Command{
|
||||||
Use: "rules",
|
Use: "rules",
|
||||||
|
Version: rootCmd.Version,
|
||||||
Short: "Rules management utility",
|
Short: "Rules management utility",
|
||||||
Long: `On each subcommand you'll have available at least two flags:
|
Long: `On each subcommand you'll have available at least two flags:
|
||||||
"username" and "id". You must either set only one of them
|
"username" and "id". You must either set only one of them
|
||||||
@ -42,14 +43,14 @@ func runRules(st *storage.Storage, cmd *cobra.Command, users func(*users.User),
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
settings, err := st.Settings.Get()
|
s, err := st.Settings.Get()
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|
||||||
if global != nil {
|
if global != nil {
|
||||||
global(settings)
|
global(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
printRules(settings.Rules, id)
|
printRules(s.Rules, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUserIdentifier(flags *pflag.FlagSet) interface{} {
|
func getUserIdentifier(flags *pflag.FlagSet) interface{} {
|
||||||
|
|||||||
@ -15,6 +15,7 @@ func init() {
|
|||||||
|
|
||||||
var upgradeCmd = &cobra.Command{
|
var upgradeCmd = &cobra.Command{
|
||||||
Use: "upgrade",
|
Use: "upgrade",
|
||||||
|
Version: rootCmd.Version,
|
||||||
Short: "Upgrades an old configuration",
|
Short: "Upgrades an old configuration",
|
||||||
Long: `Upgrades an old configuration. This command DOES NOT
|
Long: `Upgrades an old configuration. This command DOES NOT
|
||||||
import share links because they are incompatible with
|
import share links because they are incompatible with
|
||||||
@ -24,7 +25,7 @@ this version.`,
|
|||||||
flags := cmd.Flags()
|
flags := cmd.Flags()
|
||||||
oldDB := mustGetString(flags, "old.database")
|
oldDB := mustGetString(flags, "old.database")
|
||||||
oldConf := mustGetString(flags, "old.config")
|
oldConf := mustGetString(flags, "old.config")
|
||||||
err := importer.Import(oldDB, oldConf, mustGetStringViperFlag(flags, "database"))
|
err := importer.Import(oldDB, oldConf, getParam(flags, "database"))
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,6 +19,7 @@ func init() {
|
|||||||
|
|
||||||
var usersCmd = &cobra.Command{
|
var usersCmd = &cobra.Command{
|
||||||
Use: "users",
|
Use: "users",
|
||||||
|
Version: rootCmd.Version,
|
||||||
Short: "Users management utility",
|
Short: "Users management utility",
|
||||||
Long: `Users management utility.`,
|
Long: `Users management utility.`,
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
|
|||||||
@ -9,8 +9,10 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var usersExportCmd = &cobra.Command{
|
var usersExportCmd = &cobra.Command{
|
||||||
Use: "export <filename>",
|
Use: "export <path>",
|
||||||
Short: "Export all users.",
|
Short: "Export all users to a file.",
|
||||||
|
Long: `Export all users to a json or yaml file. Please indicate the
|
||||||
|
path to the file where you want to write the users.`,
|
||||||
Args: jsonYamlArg,
|
Args: jsonYamlArg,
|
||||||
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||||
list, err := d.store.Users.Gets("")
|
list, err := d.store.Users.Gets("")
|
||||||
|
|||||||
@ -16,8 +16,12 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var usersImportCmd = &cobra.Command{
|
var usersImportCmd = &cobra.Command{
|
||||||
Use: "import <filename>",
|
Use: "import <path>",
|
||||||
Short: "Import users from a file.",
|
Short: "Import users from a file",
|
||||||
|
Long: `Import users from a file. The path must be for a json or yaml
|
||||||
|
file. You can use this command to import new users to your
|
||||||
|
installation. For that, just don't place their ID on the files
|
||||||
|
list or set it to 0.`,
|
||||||
Args: jsonYamlArg,
|
Args: jsonYamlArg,
|
||||||
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||||
fd, err := os.Open(args[0])
|
fd, err := os.Open(args[0])
|
||||||
|
|||||||
@ -26,8 +26,10 @@ options you want to change.`,
|
|||||||
password := mustGetString(flags, "password")
|
password := mustGetString(flags, "password")
|
||||||
newUsername := mustGetString(flags, "username")
|
newUsername := mustGetString(flags, "username")
|
||||||
|
|
||||||
var err error
|
var (
|
||||||
var user *users.User
|
err error
|
||||||
|
user *users.User
|
||||||
|
)
|
||||||
|
|
||||||
if id != 0 {
|
if id != 0 {
|
||||||
user, err = d.store.Users.Get("", id)
|
user, err = d.store.Users.Get("", id)
|
||||||
|
|||||||
@ -19,8 +19,7 @@ import (
|
|||||||
|
|
||||||
func checkErr(err error) {
|
func checkErr(err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
log.Fatal(err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +66,7 @@ func python(fn pythonFunc, cfg pythonConfig) cobraFunc {
|
|||||||
return func(cmd *cobra.Command, args []string) {
|
return func(cmd *cobra.Command, args []string) {
|
||||||
data := pythonData{hadDB: true}
|
data := pythonData{hadDB: true}
|
||||||
|
|
||||||
path := mustGetStringViperFlag(cmd.Flags(), "database")
|
path := getParam(cmd.Flags(), "database")
|
||||||
_, err := os.Stat(path)
|
_, err := os.Stat(path)
|
||||||
|
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
|
|||||||
@ -1,20 +1,32 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"text/template"
|
||||||
|
|
||||||
"github.com/filebrowser/filebrowser/v2/version"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.AddCommand(versionCmd)
|
rootCmd.AddCommand(versionCmd)
|
||||||
|
cmdsCmd.AddCommand(versionCmd)
|
||||||
|
configCmd.AddCommand(versionCmd)
|
||||||
|
hashCmd.AddCommand(versionCmd)
|
||||||
|
upgradeCmd.AddCommand(versionCmd)
|
||||||
|
rulesCmd.AddCommand(versionCmd)
|
||||||
|
usersCmd.AddCommand(versionCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
var versionCmd = &cobra.Command{
|
var versionCmd = &cobra.Command{
|
||||||
Use: "version",
|
Use: "version",
|
||||||
Short: "Print the version number",
|
Short: "Print the version number of File Browser",
|
||||||
|
Long: `All software has versions. This is File Browser's`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
fmt.Println("File Browser Version " + version.Version)
|
// https://github.com/spf13/cobra/issues/724
|
||||||
|
t := template.New("version")
|
||||||
|
template.Must(t.Parse(rootCmd.VersionTemplate()))
|
||||||
|
err := t.Execute(rootCmd.OutOrStdout(), rootCmd)
|
||||||
|
if err != nil {
|
||||||
|
rootCmd.Println(err)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/dgrijalva/jwt-go"
|
jwt "github.com/dgrijalva/jwt-go"
|
||||||
"github.com/dgrijalva/jwt-go/request"
|
"github.com/dgrijalva/jwt-go/request"
|
||||||
"github.com/filebrowser/filebrowser/v2/errors"
|
"github.com/filebrowser/filebrowser/v2/errors"
|
||||||
"github.com/filebrowser/filebrowser/v2/users"
|
"github.com/filebrowser/filebrowser/v2/users"
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/GeertJohan/go.rice"
|
rice "github.com/GeertJohan/go.rice"
|
||||||
"github.com/filebrowser/filebrowser/v2/auth"
|
"github.com/filebrowser/filebrowser/v2/auth"
|
||||||
"github.com/filebrowser/filebrowser/v2/settings"
|
"github.com/filebrowser/filebrowser/v2/settings"
|
||||||
"github.com/filebrowser/filebrowser/v2/storage"
|
"github.com/filebrowser/filebrowser/v2/storage"
|
||||||
|
|||||||
@ -13,8 +13,8 @@ import (
|
|||||||
"github.com/asdine/storm"
|
"github.com/asdine/storm"
|
||||||
"github.com/filebrowser/filebrowser/v2/settings"
|
"github.com/filebrowser/filebrowser/v2/settings"
|
||||||
"github.com/filebrowser/filebrowser/v2/storage"
|
"github.com/filebrowser/filebrowser/v2/storage"
|
||||||
"github.com/pelletier/go-toml"
|
toml "github.com/pelletier/go-toml"
|
||||||
"gopkg.in/yaml.v2"
|
yaml "gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
type oldDefs struct {
|
type oldDefs struct {
|
||||||
@ -62,14 +62,14 @@ var defaults = &oldConf{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func importConf(db *storm.DB, path string, sto *storage.Storage) error {
|
func readConf(path string) (*oldConf, error) {
|
||||||
cfg := &oldConf{}
|
cfg := &oldConf{}
|
||||||
if path != "" {
|
if path != "" {
|
||||||
ext := filepath.Ext(path)
|
ext := filepath.Ext(path)
|
||||||
|
|
||||||
fd, err := os.Open(path)
|
fd, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer fd.Close()
|
defer fd.Close()
|
||||||
|
|
||||||
@ -81,23 +81,32 @@ func importConf(db *storm.DB, path string, sto *storage.Storage) error {
|
|||||||
case ".yaml", ".yml":
|
case ".yaml", ".yml":
|
||||||
err = yaml.NewDecoder(fd).Decode(cfg)
|
err = yaml.NewDecoder(fd).Decode(cfg)
|
||||||
default:
|
default:
|
||||||
return errors.New("unsupported config extension " + ext)
|
return nil, errors.New("unsupported config extension " + ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cfg = defaults
|
cfg = defaults
|
||||||
path, err := filepath.Abs(".")
|
path, err := filepath.Abs(".")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
cfg.Defaults.Scope = path
|
cfg.Defaults.Scope = path
|
||||||
}
|
}
|
||||||
|
return cfg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func importConf(db *storm.DB, path string, sto *storage.Storage) error {
|
||||||
|
|
||||||
|
cfg, err := readConf(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
commands := map[string][]string{}
|
commands := map[string][]string{}
|
||||||
err := db.Get("config", "commands", &commands)
|
err = db.Get("config", "commands", &commands)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,32 +12,29 @@ type usersBackend struct {
|
|||||||
db *storm.DB
|
db *storm.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st usersBackend) GetByID(id uint) (*users.User, error) {
|
func (st usersBackend) GetBy(i interface{}) (user *users.User, err error) {
|
||||||
user := &users.User{}
|
user = &users.User{}
|
||||||
err := st.db.One("ID", id, user)
|
|
||||||
|
var arg string
|
||||||
|
switch i.(type) {
|
||||||
|
case uint:
|
||||||
|
arg = "ID"
|
||||||
|
case string:
|
||||||
|
arg = "Username"
|
||||||
|
default:
|
||||||
|
return nil, errors.ErrInvalidDataType
|
||||||
|
}
|
||||||
|
|
||||||
|
err = st.db.One(arg, i, user)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
if err == storm.ErrNotFound {
|
if err == storm.ErrNotFound {
|
||||||
return nil, errors.ErrNotExist
|
return nil, errors.ErrNotExist
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return user, nil
|
return
|
||||||
}
|
|
||||||
|
|
||||||
func (st usersBackend) GetByUsername(username string) (*users.User, error) {
|
|
||||||
user := &users.User{}
|
|
||||||
err := st.db.One("Username", username, user)
|
|
||||||
if err == storm.ErrNotFound {
|
|
||||||
return nil, errors.ErrNotExist
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return user, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st usersBackend) Gets() ([]*users.User, error) {
|
func (st usersBackend) Gets() ([]*users.User, error) {
|
||||||
@ -82,7 +79,7 @@ func (st usersBackend) DeleteByID(id uint) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (st usersBackend) DeleteByUsername(username string) error {
|
func (st usersBackend) DeleteByUsername(username string) error {
|
||||||
user, err := st.GetByUsername(username)
|
user, err := st.GetBy(username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,8 +9,7 @@ import (
|
|||||||
|
|
||||||
// StorageBackend is the interface to implement for a users storage.
|
// StorageBackend is the interface to implement for a users storage.
|
||||||
type StorageBackend interface {
|
type StorageBackend interface {
|
||||||
GetByID(uint) (*User, error)
|
GetBy(interface{}) (*User, error)
|
||||||
GetByUsername(string) (*User, error)
|
|
||||||
Gets() ([]*User, error)
|
Gets() ([]*User, error)
|
||||||
Save(u *User) error
|
Save(u *User) error
|
||||||
Update(u *User, fields ...string) error
|
Update(u *User, fields ...string) error
|
||||||
@ -36,27 +35,13 @@ func NewStorage(back StorageBackend) *Storage {
|
|||||||
// Get allows you to get a user by its name or username. The provided
|
// Get allows you to get a user by its name or username. The provided
|
||||||
// id must be a string for username lookup or a uint for id lookup. If id
|
// id must be a string for username lookup or a uint for id lookup. If id
|
||||||
// is neither, a ErrInvalidDataType will be returned.
|
// is neither, a ErrInvalidDataType will be returned.
|
||||||
func (s *Storage) Get(baseScope string, id interface{}) (*User, error) {
|
func (s *Storage) Get(baseScope string, id interface{}) (user *User, err error) {
|
||||||
var (
|
user, err = s.back.GetBy(id)
|
||||||
user *User
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
switch id.(type) {
|
|
||||||
case string:
|
|
||||||
user, err = s.back.GetByUsername(id.(string))
|
|
||||||
case uint:
|
|
||||||
user, err = s.back.GetByID(id.(uint))
|
|
||||||
default:
|
|
||||||
return nil, errors.ErrInvalidDataType
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user.Clean(baseScope)
|
user.Clean(baseScope)
|
||||||
return user, err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets gets a list of all users.
|
// Gets gets a list of all users.
|
||||||
|
|||||||
@ -131,7 +131,7 @@ pushRicebox () {
|
|||||||
|
|
||||||
git clone git@github.com:filebrowser/caddy caddy
|
git clone git@github.com:filebrowser/caddy caddy
|
||||||
cd caddy
|
cd caddy
|
||||||
cp $base/http/rice-box.go ./
|
cp ../http/rice-box.go ./
|
||||||
sed -i 's/package lib/package caddy/g' ./rice-box.go
|
sed -i 's/package lib/package caddy/g' ./rice-box.go
|
||||||
git checkout -b update-rice-box origin/master
|
git checkout -b update-rice-box origin/master
|
||||||
git config --local user.name "Filebrowser Bot"
|
git config --local user.name "Filebrowser Bot"
|
||||||
@ -238,8 +238,11 @@ release () {
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
set +e
|
||||||
git rev-parse --verify --quiet release
|
git rev-parse --verify --quiet release
|
||||||
if [ $? -ne 0 ]; then
|
exitcode=$?
|
||||||
|
set -e
|
||||||
|
if [ $exitcode -ne 0 ]; then
|
||||||
git checkout -b release "$semver"
|
git checkout -b release "$semver"
|
||||||
else
|
else
|
||||||
git checkout release
|
git checkout release
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user