commit
b4b578b90f
@ -3,7 +3,7 @@ project_name: filebrowser
|
||||
build:
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
main: cli/main.go
|
||||
main: main.go
|
||||
binary: filebrowser
|
||||
goos:
|
||||
- darwin
|
||||
@ -50,8 +50,9 @@ dockers:
|
||||
goos: linux
|
||||
goarch: amd64
|
||||
goarm: ''
|
||||
image: filebrowser/filebrowser
|
||||
image_templates:
|
||||
- "filebrowser/filebrowser:latest"
|
||||
- "filebrowser/filebrowser:{{ .Tag }}"
|
||||
skip_push: true
|
||||
tag_templates:
|
||||
- "{{ .Tag }}"
|
||||
- latest
|
||||
extra_files:
|
||||
- .docker.json
|
||||
|
||||
@ -32,7 +32,7 @@ jobs:
|
||||
repo: filebrowser/filebrowser
|
||||
branch: master
|
||||
- stage: release
|
||||
script: ./wizard.sh -r
|
||||
script: ./wizard.sh -r "$TRAVIS_TAG"
|
||||
if: tag IS present
|
||||
deploy:
|
||||
provider: releases
|
||||
|
||||
@ -2,11 +2,10 @@ FROM scratch
|
||||
|
||||
COPY --from=filebrowser/dev /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
||||
|
||||
VOLUME /tmp
|
||||
VOLUME /srv
|
||||
EXPOSE 80
|
||||
|
||||
COPY .filebrowser.docker.json /.filebrowser.json
|
||||
COPY .docker.json /.filebrowser.json
|
||||
COPY filebrowser /filebrowser
|
||||
|
||||
ENTRYPOINT [ "/filebrowser" ]
|
||||
|
||||
@ -15,5 +15,5 @@ type NoAuth struct{}
|
||||
|
||||
// Auth uses authenticates user 1.
|
||||
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))
|
||||
}
|
||||
|
||||
@ -11,10 +11,11 @@ func init() {
|
||||
}
|
||||
|
||||
var cmdsCmd = &cobra.Command{
|
||||
Use: "cmds",
|
||||
Short: "Command runner management utility",
|
||||
Long: `Command runner management utility.`,
|
||||
Args: cobra.NoArgs,
|
||||
Use: "cmds",
|
||||
Version: rootCmd.Version,
|
||||
Short: "Command runner management utility",
|
||||
Long: `Command runner management utility.`,
|
||||
Args: cobra.NoArgs,
|
||||
}
|
||||
|
||||
func printEvents(m map[string][]string) {
|
||||
|
||||
@ -13,7 +13,15 @@ func init() {
|
||||
var cmdsRmCmd = &cobra.Command{
|
||||
Use: "rm <event> <index> [index_end]",
|
||||
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 {
|
||||
if err := cobra.RangeArgs(2, 3)(cmd, args); err != nil {
|
||||
return err
|
||||
|
||||
@ -20,10 +20,11 @@ func init() {
|
||||
}
|
||||
|
||||
var configCmd = &cobra.Command{
|
||||
Use: "config",
|
||||
Short: "Configuration management utility",
|
||||
Long: `Configuration management utility.`,
|
||||
Args: cobra.NoArgs,
|
||||
Use: "config",
|
||||
Version: rootCmd.Version,
|
||||
Short: "Configuration management utility",
|
||||
Long: `Configuration management utility.`,
|
||||
Args: cobra.NoArgs,
|
||||
}
|
||||
|
||||
func addConfigFlags(flags *pflag.FlagSet) {
|
||||
|
||||
@ -9,9 +9,12 @@ func init() {
|
||||
}
|
||||
|
||||
var configExportCmd = &cobra.Command{
|
||||
Use: "export <filename>",
|
||||
Short: "Export the configuration to a file.",
|
||||
Args: jsonYamlArg,
|
||||
Use: "export <path>",
|
||||
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,
|
||||
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||
settings, err := d.store.Settings.Get()
|
||||
checkErr(err)
|
||||
|
||||
@ -22,12 +22,16 @@ type settingsFile struct {
|
||||
}
|
||||
|
||||
var configImportCmd = &cobra.Command{
|
||||
Use: "import <filename>",
|
||||
Short: `Import a configuration file. This will replace all the existing
|
||||
Use: "import <path>",
|
||||
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.
|
||||
|
||||
If used with a nonexisting database, a key will be generated
|
||||
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,
|
||||
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||
var key []byte
|
||||
|
||||
@ -18,7 +18,7 @@ var configInitCmd = &cobra.Command{
|
||||
Short: "Initialize a new database",
|
||||
Long: `Initialize a new database to use with File Browser. All of
|
||||
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
|
||||
override the options.`,
|
||||
Args: cobra.NoArgs,
|
||||
|
||||
@ -17,7 +17,7 @@ var configSetCmd = &cobra.Command{
|
||||
Use: "set",
|
||||
Short: "Updates the configuration",
|
||||
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,
|
||||
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||
flags := cmd.Flags()
|
||||
|
||||
@ -9,8 +9,8 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
@ -12,10 +12,11 @@ func init() {
|
||||
}
|
||||
|
||||
var hashCmd = &cobra.Command{
|
||||
Use: "hash <password>",
|
||||
Short: "Hashes a password",
|
||||
Long: `Hashes a password using bcrypt algorithm.`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Use: "hash <password>",
|
||||
Version: rootCmd.Version,
|
||||
Short: "Hashes a password",
|
||||
Long: `Hashes a password using bcrypt algorithm.`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
pwd, err := users.HashPwd(args[0])
|
||||
checkErr(err)
|
||||
|
||||
167
cmd/root.go
167
cmd/root.go
@ -2,7 +2,6 @@ package cmd
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
@ -16,7 +15,8 @@ import (
|
||||
"github.com/filebrowser/filebrowser/v2/settings"
|
||||
"github.com/filebrowser/filebrowser/v2/storage"
|
||||
"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/pflag"
|
||||
v "github.com/spf13/viper"
|
||||
@ -29,11 +29,15 @@ var (
|
||||
|
||||
func init() {
|
||||
cobra.OnInitialize(initConfig)
|
||||
|
||||
rootCmd.SetVersionTemplate("File Browser version {{printf \"%s\" .Version}}\n")
|
||||
|
||||
flags := rootCmd.Flags()
|
||||
persistent := rootCmd.PersistentFlags()
|
||||
|
||||
persistent.StringVarP(&cfgFile, "config", "c", "", "config file 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("password", "", "hashed password for the first user when using quick config (default \"admin\")")
|
||||
|
||||
@ -50,49 +54,14 @@ func addServerFlags(flags *pflag.FlagSet) {
|
||||
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{
|
||||
Use: "filebrowser",
|
||||
Short: "A stylish web-based file browser",
|
||||
Use: "filebrowser",
|
||||
Version: version.Version,
|
||||
Short: "A stylish web-based 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
|
||||
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
|
||||
@ -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:
|
||||
|
||||
- flag
|
||||
- environment variable
|
||||
- flags
|
||||
- environment variables
|
||||
- configuration file
|
||||
- database values
|
||||
- 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.
|
||||
set FB_DATABASE.
|
||||
|
||||
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: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||
log.Println(cfgFile)
|
||||
|
||||
if !d.hadDB {
|
||||
quickSetup(cmd.Flags(), d)
|
||||
}
|
||||
|
||||
server := getServerWithViper(cmd.Flags(), d.store)
|
||||
server := getRunParams(cmd.Flags(), d.store)
|
||||
setupLog(server.Log)
|
||||
|
||||
root, err := filepath.Abs(server.Root)
|
||||
checkErr(err)
|
||||
server.Root = root
|
||||
|
||||
handler, err := fbhttp.NewHandler(d.store, server)
|
||||
checkErr(err)
|
||||
adr := server.Address + ":" + server.Port
|
||||
|
||||
var listener net.Listener
|
||||
|
||||
if server.TLSKey != "" && server.TLSCert != "" {
|
||||
cer, err := tls.LoadX509KeyPair(server.TLSCert, server.TLSKey)
|
||||
checkErr(err)
|
||||
config := &tls.Config{Certificates: []tls.Certificate{cer}}
|
||||
listener, err = tls.Listen("tcp", server.Address+":"+server.Port, config)
|
||||
listener, err = tls.Listen("tcp", adr, &tls.Config{Certificates: []tls.Certificate{cer}})
|
||||
checkErr(err)
|
||||
} else {
|
||||
listener, err = net.Listen("tcp", server.Address+":"+server.Port)
|
||||
listener, err = net.Listen("tcp", adr)
|
||||
checkErr(err)
|
||||
}
|
||||
|
||||
handler, err := fbhttp.NewHandler(d.store, server)
|
||||
checkErr(err)
|
||||
|
||||
log.Println("Listening on", listener.Addr().String())
|
||||
if err := http.Serve(listener, handler); err != nil {
|
||||
log.Fatal(err)
|
||||
@ -158,41 +131,70 @@ user created with the credentials from options "username" and "password".`,
|
||||
}, 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()
|
||||
checkErr(err)
|
||||
|
||||
if val, set := getStringViperFlag(flags, "root"); set {
|
||||
if val, set := getParamB(flags, "root"); set {
|
||||
server.Root = val
|
||||
}
|
||||
|
||||
if val, set := getStringViperFlag(flags, "baseurl"); set {
|
||||
if val, set := getParamB(flags, "baseurl"); set {
|
||||
server.BaseURL = val
|
||||
}
|
||||
|
||||
if val, set := getStringViperFlag(flags, "address"); set {
|
||||
if val, set := getParamB(flags, "address"); set {
|
||||
server.Address = val
|
||||
}
|
||||
|
||||
if val, set := getStringViperFlag(flags, "port"); set {
|
||||
if val, set := getParamB(flags, "port"); set {
|
||||
server.Port = val
|
||||
}
|
||||
|
||||
if val, set := getStringViperFlag(flags, "log"); set {
|
||||
if val, set := getParamB(flags, "log"); set {
|
||||
server.Log = val
|
||||
}
|
||||
|
||||
if val, set := getStringViperFlag(flags, "key"); set {
|
||||
if val, set := getParamB(flags, "key"); set {
|
||||
server.TLSKey = val
|
||||
}
|
||||
|
||||
if val, set := getStringViperFlag(flags, "cert"); set {
|
||||
if val, set := getParamB(flags, "cert"); set {
|
||||
server.TLSCert = val
|
||||
}
|
||||
|
||||
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) {
|
||||
switch logMethod {
|
||||
case "stdout":
|
||||
@ -209,14 +211,12 @@ func setupLog(logMethod string) {
|
||||
MaxBackups: 10,
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func quickSetup(flags *pflag.FlagSet, d pythonData) {
|
||||
set := &settings.Settings{
|
||||
Key: generateRandomBytes(64), // 256 bit
|
||||
Signup: false,
|
||||
AuthMethod: auth.MethodJSONAuth,
|
||||
Key: generateRandomBytes(64), // 256 bit
|
||||
Signup: false,
|
||||
Defaults: settings.UserDefaults{
|
||||
Scope: ".",
|
||||
Locale: "en",
|
||||
@ -233,27 +233,34 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) {
|
||||
},
|
||||
}
|
||||
|
||||
ser := &settings.Server{
|
||||
BaseURL: mustGetStringViperFlag(flags, "baseurl"),
|
||||
Port: mustGetStringViperFlag(flags, "port"),
|
||||
Log: mustGetStringViperFlag(flags, "log"),
|
||||
TLSKey: mustGetStringViperFlag(flags, "key"),
|
||||
TLSCert: mustGetStringViperFlag(flags, "cert"),
|
||||
Address: mustGetStringViperFlag(flags, "address"),
|
||||
Root: mustGetStringViperFlag(flags, "root"),
|
||||
var err error
|
||||
if _, noauth := getParamB(flags, "noauth"); noauth {
|
||||
set.AuthMethod = auth.MethodNoAuth
|
||||
err = d.store.Auth.Save(&auth.NoAuth{})
|
||||
} else {
|
||||
set.AuthMethod = auth.MethodJSONAuth
|
||||
err = d.store.Auth.Save(&auth.JSONAuth{})
|
||||
}
|
||||
|
||||
err := d.store.Settings.Save(set)
|
||||
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)
|
||||
checkErr(err)
|
||||
|
||||
err = d.store.Auth.Save(&auth.JSONAuth{})
|
||||
checkErr(err)
|
||||
|
||||
username := mustGetStringViperFlag(flags, "username")
|
||||
password := mustGetStringViperFlag(flags, "password")
|
||||
username := getParam(flags, "username")
|
||||
password := getParam(flags, "password")
|
||||
|
||||
if password == "" {
|
||||
password, err = users.HashPwd("admin")
|
||||
@ -261,7 +268,7 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) {
|
||||
}
|
||||
|
||||
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{
|
||||
@ -297,7 +304,9 @@ func initConfig() {
|
||||
if _, ok := err.(v.ConfigParseError); ok {
|
||||
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{
|
||||
Use: "rm <index> [index_end]",
|
||||
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 {
|
||||
if err := cobra.RangeArgs(1, 2)(cmd, args); err != nil {
|
||||
return err
|
||||
|
||||
11
cmd/rules.go
11
cmd/rules.go
@ -18,8 +18,9 @@ func init() {
|
||||
}
|
||||
|
||||
var rulesCmd = &cobra.Command{
|
||||
Use: "rules",
|
||||
Short: "Rules management utility",
|
||||
Use: "rules",
|
||||
Version: rootCmd.Version,
|
||||
Short: "Rules management utility",
|
||||
Long: `On each subcommand you'll have available at least two flags:
|
||||
"username" and "id". You must either set only one of them
|
||||
or none. If you set one of them, the command will apply to
|
||||
@ -42,14 +43,14 @@ func runRules(st *storage.Storage, cmd *cobra.Command, users func(*users.User),
|
||||
return
|
||||
}
|
||||
|
||||
settings, err := st.Settings.Get()
|
||||
s, err := st.Settings.Get()
|
||||
checkErr(err)
|
||||
|
||||
if global != nil {
|
||||
global(settings)
|
||||
global(s)
|
||||
}
|
||||
|
||||
printRules(settings.Rules, id)
|
||||
printRules(s.Rules, id)
|
||||
}
|
||||
|
||||
func getUserIdentifier(flags *pflag.FlagSet) interface{} {
|
||||
|
||||
@ -14,8 +14,9 @@ func init() {
|
||||
}
|
||||
|
||||
var upgradeCmd = &cobra.Command{
|
||||
Use: "upgrade",
|
||||
Short: "Upgrades an old configuration",
|
||||
Use: "upgrade",
|
||||
Version: rootCmd.Version,
|
||||
Short: "Upgrades an old configuration",
|
||||
Long: `Upgrades an old configuration. This command DOES NOT
|
||||
import share links because they are incompatible with
|
||||
this version.`,
|
||||
@ -24,7 +25,7 @@ this version.`,
|
||||
flags := cmd.Flags()
|
||||
oldDB := mustGetString(flags, "old.database")
|
||||
oldConf := mustGetString(flags, "old.config")
|
||||
err := importer.Import(oldDB, oldConf, mustGetStringViperFlag(flags, "database"))
|
||||
err := importer.Import(oldDB, oldConf, getParam(flags, "database"))
|
||||
checkErr(err)
|
||||
},
|
||||
}
|
||||
|
||||
@ -18,10 +18,11 @@ func init() {
|
||||
}
|
||||
|
||||
var usersCmd = &cobra.Command{
|
||||
Use: "users",
|
||||
Short: "Users management utility",
|
||||
Long: `Users management utility.`,
|
||||
Args: cobra.NoArgs,
|
||||
Use: "users",
|
||||
Version: rootCmd.Version,
|
||||
Short: "Users management utility",
|
||||
Long: `Users management utility.`,
|
||||
Args: cobra.NoArgs,
|
||||
}
|
||||
|
||||
func printUsers(users []*users.User) {
|
||||
|
||||
@ -9,9 +9,11 @@ func init() {
|
||||
}
|
||||
|
||||
var usersExportCmd = &cobra.Command{
|
||||
Use: "export <filename>",
|
||||
Short: "Export all users.",
|
||||
Args: jsonYamlArg,
|
||||
Use: "export <path>",
|
||||
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,
|
||||
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||
list, err := d.store.Users.Gets("")
|
||||
checkErr(err)
|
||||
|
||||
@ -16,9 +16,13 @@ func init() {
|
||||
}
|
||||
|
||||
var usersImportCmd = &cobra.Command{
|
||||
Use: "import <filename>",
|
||||
Short: "Import users from a file.",
|
||||
Args: jsonYamlArg,
|
||||
Use: "import <path>",
|
||||
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,
|
||||
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||
fd, err := os.Open(args[0])
|
||||
checkErr(err)
|
||||
@ -36,16 +40,16 @@ var usersImportCmd = &cobra.Command{
|
||||
if mustGetBool(cmd.Flags(), "replace") {
|
||||
oldUsers, err := d.store.Users.Gets("")
|
||||
checkErr(err)
|
||||
|
||||
|
||||
err = marshal("users.backup.json", list)
|
||||
checkErr(err)
|
||||
|
||||
|
||||
for _, user := range oldUsers {
|
||||
err = d.store.Users.Delete(user.ID)
|
||||
checkErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
overwrite := mustGetBool(cmd.Flags(), "overwrite")
|
||||
|
||||
for _, user := range list {
|
||||
|
||||
@ -26,8 +26,10 @@ options you want to change.`,
|
||||
password := mustGetString(flags, "password")
|
||||
newUsername := mustGetString(flags, "username")
|
||||
|
||||
var err error
|
||||
var user *users.User
|
||||
var (
|
||||
err error
|
||||
user *users.User
|
||||
)
|
||||
|
||||
if id != 0 {
|
||||
user, err = d.store.Users.Get("", id)
|
||||
|
||||
@ -19,8 +19,7 @@ import (
|
||||
|
||||
func checkErr(err error) {
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,7 +66,7 @@ func python(fn pythonFunc, cfg pythonConfig) cobraFunc {
|
||||
return func(cmd *cobra.Command, args []string) {
|
||||
data := pythonData{hadDB: true}
|
||||
|
||||
path := mustGetStringViperFlag(cmd.Flags(), "database")
|
||||
path := getParam(cmd.Flags(), "database")
|
||||
_, err := os.Stat(path)
|
||||
|
||||
if os.IsNotExist(err) {
|
||||
|
||||
@ -1,20 +1,32 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"text/template"
|
||||
|
||||
"github.com/filebrowser/filebrowser/v2/version"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
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{
|
||||
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) {
|
||||
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"
|
||||
"time"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
jwt "github.com/dgrijalva/jwt-go"
|
||||
"github.com/dgrijalva/jwt-go/request"
|
||||
"github.com/filebrowser/filebrowser/v2/errors"
|
||||
"github.com/filebrowser/filebrowser/v2/users"
|
||||
|
||||
@ -9,7 +9,7 @@ import (
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/GeertJohan/go.rice"
|
||||
rice "github.com/GeertJohan/go.rice"
|
||||
"github.com/filebrowser/filebrowser/v2/auth"
|
||||
"github.com/filebrowser/filebrowser/v2/settings"
|
||||
"github.com/filebrowser/filebrowser/v2/storage"
|
||||
|
||||
@ -13,8 +13,8 @@ import (
|
||||
"github.com/asdine/storm"
|
||||
"github.com/filebrowser/filebrowser/v2/settings"
|
||||
"github.com/filebrowser/filebrowser/v2/storage"
|
||||
"github.com/pelletier/go-toml"
|
||||
"gopkg.in/yaml.v2"
|
||||
toml "github.com/pelletier/go-toml"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type oldDefs struct {
|
||||
@ -33,7 +33,7 @@ type oldAuth struct {
|
||||
}
|
||||
|
||||
type oldConf struct {
|
||||
Port string `json:"port" yaml:"port" toml:"port"`
|
||||
Port string `json:"port" yaml:"port" toml:"port"`
|
||||
BaseURL string `json:"baseURL" yaml:"baseURL" toml:"baseURL"`
|
||||
Log string `json:"log" yaml:"log" toml:"log"`
|
||||
Address string `json:"address" yaml:"address" toml:"address"`
|
||||
@ -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{}
|
||||
if path != "" {
|
||||
ext := filepath.Ext(path)
|
||||
|
||||
fd, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
@ -81,23 +81,32 @@ func importConf(db *storm.DB, path string, sto *storage.Storage) error {
|
||||
case ".yaml", ".yml":
|
||||
err = yaml.NewDecoder(fd).Decode(cfg)
|
||||
default:
|
||||
return errors.New("unsupported config extension " + ext)
|
||||
return nil, errors.New("unsupported config extension " + ext)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
cfg = defaults
|
||||
path, err := filepath.Abs(".")
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
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{}
|
||||
err := db.Get("config", "commands", &commands)
|
||||
err = db.Get("config", "commands", &commands)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -109,8 +118,8 @@ func importConf(db *storm.DB, path string, sto *storage.Storage) error {
|
||||
}
|
||||
|
||||
s := &settings.Settings{
|
||||
Key: key,
|
||||
Signup: false,
|
||||
Key: key,
|
||||
Signup: false,
|
||||
Defaults: settings.UserDefaults{
|
||||
Scope: cfg.Defaults.Scope,
|
||||
Commands: cfg.Defaults.Commands,
|
||||
@ -130,10 +139,10 @@ func importConf(db *storm.DB, path string, sto *storage.Storage) error {
|
||||
}
|
||||
|
||||
server := &settings.Server{
|
||||
BaseURL : cfg.BaseURL,
|
||||
Port : cfg.Port,
|
||||
Address : cfg.Address,
|
||||
Log : cfg.Log,
|
||||
BaseURL: cfg.BaseURL,
|
||||
Port: cfg.Port,
|
||||
Address: cfg.Address,
|
||||
Log: cfg.Log,
|
||||
}
|
||||
|
||||
var auther auth.Auther
|
||||
|
||||
@ -12,32 +12,29 @@ type usersBackend struct {
|
||||
db *storm.DB
|
||||
}
|
||||
|
||||
func (st usersBackend) GetByID(id uint) (*users.User, error) {
|
||||
user := &users.User{}
|
||||
err := st.db.One("ID", id, user)
|
||||
if err == storm.ErrNotFound {
|
||||
return nil, errors.ErrNotExist
|
||||
func (st usersBackend) GetBy(i interface{}) (user *users.User, err error) {
|
||||
user = &users.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 {
|
||||
return nil, errors.ErrNotExist
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
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
|
||||
return
|
||||
}
|
||||
|
||||
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 {
|
||||
user, err := st.GetByUsername(username)
|
||||
user, err := st.GetBy(username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -9,8 +9,7 @@ import (
|
||||
|
||||
// StorageBackend is the interface to implement for a users storage.
|
||||
type StorageBackend interface {
|
||||
GetByID(uint) (*User, error)
|
||||
GetByUsername(string) (*User, error)
|
||||
GetBy(interface{}) (*User, error)
|
||||
Gets() ([]*User, error)
|
||||
Save(u *User) 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
|
||||
// id must be a string for username lookup or a uint for id lookup. If id
|
||||
// is neither, a ErrInvalidDataType will be returned.
|
||||
func (s *Storage) Get(baseScope string, id interface{}) (*User, error) {
|
||||
var (
|
||||
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
|
||||
}
|
||||
|
||||
func (s *Storage) Get(baseScope string, id interface{}) (user *User, err error) {
|
||||
user, err = s.back.GetBy(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return
|
||||
}
|
||||
|
||||
user.Clean(baseScope)
|
||||
return user, err
|
||||
return
|
||||
}
|
||||
|
||||
// Gets gets a list of all users.
|
||||
|
||||
@ -131,7 +131,7 @@ pushRicebox () {
|
||||
|
||||
git clone git@github.com:filebrowser/caddy 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
|
||||
git checkout -b update-rice-box origin/master
|
||||
git config --local user.name "Filebrowser Bot"
|
||||
@ -238,8 +238,11 @@ release () {
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set +e
|
||||
git rev-parse --verify --quiet release
|
||||
if [ $? -ne 0 ]; then
|
||||
exitcode=$?
|
||||
set -e
|
||||
if [ $exitcode -ne 0 ]; then
|
||||
git checkout -b release "$semver"
|
||||
else
|
||||
git checkout release
|
||||
|
||||
Loading…
Reference in New Issue
Block a user