feat: v2 (#599)
Read https://github.com/filebrowser/filebrowser/pull/575. Former-commit-id: 7aedcaaf72b863033e3f089d6df308d41a3fd00c [formerly bdbe4d49161b901c4adf9c245895a1be2d62e4a7] [formerly acfc1ec67c423e0b3e065a8c1f8897c5249af65b [formerly d309066def8319e9da89d00ca6463ec4aea62d34]] Former-commit-id: 0c7d925a38a68ccabdf2c4bbd8c302ee89b93509 [formerly a6173925a1382955d93b334ded93f70d6dddd694] Former-commit-id: e032e0804dd051df86f42962de2b39caec5318b7
This commit is contained in:
12
cmd/cmd.go
Normal file
12
cmd/cmd.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"log"
|
||||
)
|
||||
|
||||
// Execute executes the commands.
|
||||
func Execute() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
31
cmd/cmds.go
Normal file
31
cmd/cmds.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(cmdsCmd)
|
||||
}
|
||||
|
||||
var cmdsCmd = &cobra.Command{
|
||||
Use: "cmds",
|
||||
Short: "Command runner management utility",
|
||||
Long: `Command runner management utility.`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmd.Help()
|
||||
os.Exit(0)
|
||||
},
|
||||
}
|
||||
|
||||
func printEvents(m map[string][]string) {
|
||||
for evt, cmds := range m {
|
||||
for i, cmd := range cmds {
|
||||
fmt.Printf("%s(%d): %s\n", evt, i, cmd)
|
||||
}
|
||||
}
|
||||
}
|
||||
35
cmd/cmds_add.go
Normal file
35
cmd/cmds_add.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"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",
|
||||
Short: "Add a command to run on a specific event",
|
||||
Long: `Add a command to run on a specific event.`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
db := getDB()
|
||||
defer db.Close()
|
||||
st := getStorage(db)
|
||||
s, err := st.Settings.Get()
|
||||
checkErr(err)
|
||||
|
||||
evt := mustGetString(cmd, "event")
|
||||
command := mustGetString(cmd, "command")
|
||||
|
||||
s.Commands[evt] = append(s.Commands[evt], command)
|
||||
err = st.Settings.Save(s)
|
||||
checkErr(err)
|
||||
printEvents(s.Commands)
|
||||
},
|
||||
}
|
||||
34
cmd/cmds_ls.go
Normal file
34
cmd/cmds_ls.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cmdsCmd.AddCommand(cmdsLsCmd)
|
||||
cmdsLsCmd.Flags().StringP("event", "e", "", "event name, without 'before' or 'after'")
|
||||
}
|
||||
|
||||
var cmdsLsCmd = &cobra.Command{
|
||||
Use: "ls",
|
||||
Short: "List all commands for each event",
|
||||
Long: `List all commands for each event.`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
db := getDB()
|
||||
defer db.Close()
|
||||
st := getStorage(db)
|
||||
s, err := st.Settings.Get()
|
||||
checkErr(err)
|
||||
evt := mustGetString(cmd, "event")
|
||||
|
||||
if evt == "" {
|
||||
printEvents(s.Commands)
|
||||
} else {
|
||||
show := map[string][]string{}
|
||||
show["before_"+evt] = s.Commands["before_"+evt]
|
||||
show["after_"+evt] = s.Commands["after_"+evt]
|
||||
printEvents(show)
|
||||
}
|
||||
},
|
||||
}
|
||||
36
cmd/cmds_rm.go
Normal file
36
cmd/cmds_rm.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"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",
|
||||
Short: "Removes a command from an event hooker",
|
||||
Long: `Removes a command from an event hooker.`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
db := getDB()
|
||||
defer db.Close()
|
||||
st := getStorage(db)
|
||||
s, err := st.Settings.Get()
|
||||
checkErr(err)
|
||||
|
||||
evt := mustGetString(cmd, "event")
|
||||
i, err := cmd.Flags().GetUint("index")
|
||||
checkErr(err)
|
||||
|
||||
s.Commands[evt] = append(s.Commands[evt][:i], s.Commands[evt][i+1:]...)
|
||||
err = st.Settings.Save(s)
|
||||
checkErr(err)
|
||||
printEvents(s.Commands)
|
||||
},
|
||||
}
|
||||
136
cmd/config.go
Normal file
136
cmd/config.go
Normal file
@@ -0,0 +1,136 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
nerrors "errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/filebrowser/filebrowser/v2/auth"
|
||||
"github.com/filebrowser/filebrowser/v2/errors"
|
||||
"github.com/filebrowser/filebrowser/v2/settings"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(configCmd)
|
||||
}
|
||||
|
||||
var configCmd = &cobra.Command{
|
||||
Use: "config",
|
||||
Short: "Configuration management utility",
|
||||
Long: `Configuration management utility.`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmd.Help()
|
||||
os.Exit(0)
|
||||
},
|
||||
}
|
||||
|
||||
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")
|
||||
|
||||
cmd.Flags().StringP("address", "a", "127.0.0.1", "default address to listen to")
|
||||
cmd.Flags().StringP("log", "l", "stderr", "log output")
|
||||
cmd.Flags().IntP("port", "p", 0, "default port to listen to")
|
||||
cmd.Flags().String("tls.cert", "", "tls certificate path")
|
||||
cmd.Flags().String("tls.key", "", "tls key path")
|
||||
|
||||
cmd.Flags().String("auth.method", string(auth.MethodJSONAuth), "authentication type")
|
||||
cmd.Flags().String("auth.header", "", "HTTP header for auth.method=proxy")
|
||||
|
||||
cmd.Flags().String("recaptcha.host", "https://www.google.com", "use another host for ReCAPTCHA. recaptcha.net might be useful in China")
|
||||
cmd.Flags().String("recaptcha.key", "", "ReCaptcha site key")
|
||||
cmd.Flags().String("recaptcha.secret", "", "ReCaptcha secret")
|
||||
|
||||
cmd.Flags().String("branding.name", "", "replace 'File Browser' by this name")
|
||||
cmd.Flags().String("branding.files", "", "path to directory with images and custom styles")
|
||||
cmd.Flags().Bool("branding.disableExternal", false, "disable external links such as GitHub links")
|
||||
}
|
||||
|
||||
func getAuthentication(cmd *cobra.Command) (settings.AuthMethod, auth.Auther) {
|
||||
method := settings.AuthMethod(mustGetString(cmd, "auth.method"))
|
||||
|
||||
var auther auth.Auther
|
||||
if method == auth.MethodProxyAuth {
|
||||
header := mustGetString(cmd, "auth.header")
|
||||
if header == "" {
|
||||
panic(nerrors.New("you must set the flag 'auth.header' for method 'proxy'"))
|
||||
}
|
||||
auther = &auth.ProxyAuth{Header: header}
|
||||
}
|
||||
|
||||
if method == auth.MethodNoAuth {
|
||||
auther = &auth.NoAuth{}
|
||||
}
|
||||
|
||||
if method == auth.MethodJSONAuth {
|
||||
jsonAuth := &auth.JSONAuth{}
|
||||
|
||||
host := mustGetString(cmd, "recaptcha.host")
|
||||
key := mustGetString(cmd, "recaptcha.key")
|
||||
secret := mustGetString(cmd, "recaptcha.secret")
|
||||
|
||||
if key != "" && secret != "" {
|
||||
jsonAuth.ReCaptcha = &auth.ReCaptcha{
|
||||
Host: host,
|
||||
Key: key,
|
||||
Secret: secret,
|
||||
}
|
||||
}
|
||||
|
||||
auther = jsonAuth
|
||||
}
|
||||
|
||||
if auther == nil {
|
||||
panic(errors.ErrInvalidAuthMethod)
|
||||
}
|
||||
|
||||
return method, 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, " "))
|
||||
fmt.Fprintf(w, "Log:\t%s\t\n", s.Log)
|
||||
fmt.Fprintln(w, "\nServer:")
|
||||
fmt.Fprintf(w, "\tAddress:\t%s\n", s.Server.Address)
|
||||
fmt.Fprintf(w, "\tPort:\t%d\n", s.Server.Port)
|
||||
fmt.Fprintf(w, "\tTLS Cert:\t%s\n", s.Server.TLSCert)
|
||||
fmt.Fprintf(w, "\tTLS Key:\t%s\n", s.Server.TLSKey)
|
||||
fmt.Fprintln(w, "\nBranding:")
|
||||
fmt.Fprintf(w, "\tName:\t%s\n", s.Branding.Name)
|
||||
fmt.Fprintf(w, "\tFiles override:\t%s\n", s.Branding.Files)
|
||||
fmt.Fprintf(w, "\tDisable external links:\t%t\n", s.Branding.DisableExternal)
|
||||
fmt.Fprintln(w, "\nDefaults:")
|
||||
fmt.Fprintf(w, "\tScope:\t%s\n", s.Defaults.Scope)
|
||||
fmt.Fprintf(w, "\tLocale:\t%s\n", s.Defaults.Locale)
|
||||
fmt.Fprintf(w, "\tView mode:\t%s\n", s.Defaults.ViewMode)
|
||||
fmt.Fprintf(w, "\tCommands:\t%s\n", strings.Join(s.Defaults.Commands, " "))
|
||||
fmt.Fprintf(w, "\tSorting:\n")
|
||||
fmt.Fprintf(w, "\t\tBy:\t%s\n", s.Defaults.Sorting.By)
|
||||
fmt.Fprintf(w, "\t\tAsc:\t%t\n", s.Defaults.Sorting.Asc)
|
||||
fmt.Fprintf(w, "\tPermissions:\n")
|
||||
fmt.Fprintf(w, "\t\tAdmin:\t%t\n", s.Defaults.Perm.Admin)
|
||||
fmt.Fprintf(w, "\t\tExecute:\t%t\n", s.Defaults.Perm.Execute)
|
||||
fmt.Fprintf(w, "\t\tCreate:\t%t\n", s.Defaults.Perm.Create)
|
||||
fmt.Fprintf(w, "\t\tRename:\t%t\n", s.Defaults.Perm.Rename)
|
||||
fmt.Fprintf(w, "\t\tModify:\t%t\n", s.Defaults.Perm.Modify)
|
||||
fmt.Fprintf(w, "\t\tDelete:\t%t\n", s.Defaults.Perm.Delete)
|
||||
fmt.Fprintf(w, "\t\tShare:\t%t\n", s.Defaults.Perm.Share)
|
||||
fmt.Fprintf(w, "\t\tDownload:\t%t\n", s.Defaults.Perm.Download)
|
||||
w.Flush()
|
||||
|
||||
b, err := json.MarshalIndent(auther, "", " ")
|
||||
checkErr(err)
|
||||
fmt.Printf("\nAuther configuration (raw):\n\n%s\n\n", string(b))
|
||||
}
|
||||
26
cmd/config_cat.go
Normal file
26
cmd/config_cat.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
configCmd.AddCommand(configCatCmd)
|
||||
}
|
||||
|
||||
var configCatCmd = &cobra.Command{
|
||||
Use: "cat",
|
||||
Short: "Prints the configuration",
|
||||
Long: `Prints the configuration.`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
db := getDB()
|
||||
defer db.Close()
|
||||
st := getStorage(db)
|
||||
s, err := st.Settings.Get()
|
||||
checkErr(err)
|
||||
auther, err := st.Auth.Get(s.AuthMethod)
|
||||
checkErr(err)
|
||||
printSettings(s, auther)
|
||||
},
|
||||
}
|
||||
76
cmd/config_init.go
Normal file
76
cmd/config_init.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/asdine/storm"
|
||||
"github.com/filebrowser/filebrowser/v2/settings"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
configCmd.AddCommand(configInitCmd)
|
||||
rootCmd.AddCommand(configInitCmd)
|
||||
addConfigFlags(configInitCmd)
|
||||
configInitCmd.MarkFlagRequired("scope")
|
||||
}
|
||||
|
||||
var configInitCmd = &cobra.Command{
|
||||
Use: "init",
|
||||
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
|
||||
to the defaults when creating new users and you don't
|
||||
override the options.`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if _, err := os.Stat(databasePath); err == nil {
|
||||
panic(errors.New(databasePath + " already exists"))
|
||||
}
|
||||
|
||||
defaults := settings.UserDefaults{}
|
||||
getUserDefaults(cmd, &defaults, true)
|
||||
authMethod, auther := getAuthentication(cmd)
|
||||
|
||||
db, err := storm.Open(databasePath)
|
||||
checkErr(err)
|
||||
defer db.Close()
|
||||
st := getStorage(db)
|
||||
s := &settings.Settings{
|
||||
Key: generateRandomBytes(64), // 256 bit
|
||||
BaseURL: mustGetString(cmd, "baseURL"),
|
||||
Log: mustGetString(cmd, "log"),
|
||||
Signup: mustGetBool(cmd, "signup"),
|
||||
Shell: strings.Split(strings.TrimSpace(mustGetString(cmd, "shell")), " "),
|
||||
AuthMethod: authMethod,
|
||||
Defaults: defaults,
|
||||
Server: settings.Server{
|
||||
Address: mustGetString(cmd, "address"),
|
||||
Port: mustGetInt(cmd, "port"),
|
||||
TLSCert: mustGetString(cmd, "tls.cert"),
|
||||
TLSKey: mustGetString(cmd, "tls.key"),
|
||||
},
|
||||
Branding: settings.Branding{
|
||||
Name: mustGetString(cmd, "branding.name"),
|
||||
DisableExternal: mustGetBool(cmd, "branding.disableExternal"),
|
||||
Files: mustGetString(cmd, "branding.files"),
|
||||
},
|
||||
}
|
||||
|
||||
err = st.Settings.Save(s)
|
||||
checkErr(err)
|
||||
err = st.Auth.Save(auther)
|
||||
checkErr(err)
|
||||
|
||||
fmt.Printf(`
|
||||
Congratulations! You've set up your database to use with File Browser.
|
||||
Now add your first user via 'filebrowser users new' and then you just
|
||||
need to call the main command to boot up the server.
|
||||
`)
|
||||
printSettings(s, auther)
|
||||
},
|
||||
}
|
||||
76
cmd/config_set.go
Normal file
76
cmd/config_set.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/filebrowser/filebrowser/v2/auth"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
func init() {
|
||||
configCmd.AddCommand(configSetCmd)
|
||||
addConfigFlags(configSetCmd)
|
||||
}
|
||||
|
||||
var configSetCmd = &cobra.Command{
|
||||
Use: "set",
|
||||
Short: "Updates the configuration",
|
||||
Long: `Updates the configuration. Set the flags for the options
|
||||
you want to change.`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
db := getDB()
|
||||
defer db.Close()
|
||||
|
||||
st := getStorage(db)
|
||||
s, err := st.Settings.Get()
|
||||
checkErr(err)
|
||||
|
||||
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":
|
||||
hasAuth = true
|
||||
case "shell":
|
||||
s.Shell = strings.Split(strings.TrimSpace(mustGetString(cmd, flag.Name)), " ")
|
||||
case "branding.name":
|
||||
s.Branding.Name = mustGetString(cmd, flag.Name)
|
||||
case "branding.disableExternal":
|
||||
s.Branding.DisableExternal = mustGetBool(cmd, flag.Name)
|
||||
case "branding.files":
|
||||
s.Branding.Files = mustGetString(cmd, flag.Name)
|
||||
case "log":
|
||||
s.Log = mustGetString(cmd, flag.Name)
|
||||
case "address":
|
||||
s.Server.Address = mustGetString(cmd, flag.Name)
|
||||
case "port":
|
||||
s.Server.Port = mustGetInt(cmd, flag.Name)
|
||||
case "tls.cert":
|
||||
s.Server.TLSCert = mustGetString(cmd, flag.Name)
|
||||
case "tls.key":
|
||||
s.Server.TLSKey = mustGetString(cmd, flag.Name)
|
||||
}
|
||||
})
|
||||
|
||||
getUserDefaults(cmd, &s.Defaults, false)
|
||||
|
||||
var auther auth.Auther
|
||||
if hasAuth {
|
||||
s.AuthMethod, auther = getAuthentication(cmd)
|
||||
err = st.Auth.Save(auther)
|
||||
checkErr(err)
|
||||
} else {
|
||||
auther, err = st.Auth.Get(s.AuthMethod)
|
||||
checkErr(err)
|
||||
}
|
||||
|
||||
err = st.Settings.Save(s)
|
||||
checkErr(err)
|
||||
printSettings(s, auther)
|
||||
},
|
||||
}
|
||||
129
cmd/docs.go
Normal file
129
cmd/docs.go
Normal file
@@ -0,0 +1,129 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(docsCmd)
|
||||
docsCmd.Flags().StringP("path", "p", "./docs", "path to save the docs")
|
||||
}
|
||||
|
||||
func printToc(names []string) {
|
||||
for i, name := range names {
|
||||
name = strings.TrimSuffix(name, filepath.Ext(name))
|
||||
name = strings.Replace(name, "-", " ", -1)
|
||||
names[i] = name
|
||||
}
|
||||
|
||||
sort.Strings(names)
|
||||
|
||||
toc := ""
|
||||
for _, name := range names {
|
||||
toc += "* [" + name + "](cli/" + strings.Replace(name, " ", "-", -1) + ".md)\n"
|
||||
}
|
||||
|
||||
fmt.Println(toc)
|
||||
}
|
||||
|
||||
var docsCmd = &cobra.Command{
|
||||
Use: "docs",
|
||||
Hidden: true,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
dir := mustGetString(cmd, "path")
|
||||
generateDocs(rootCmd, dir)
|
||||
names := []string{}
|
||||
|
||||
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil || info.IsDir() {
|
||||
return err
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(info.Name(), "filebrowser") {
|
||||
return nil
|
||||
}
|
||||
|
||||
names = append(names, info.Name())
|
||||
return nil
|
||||
})
|
||||
|
||||
checkErr(err)
|
||||
printToc(names)
|
||||
},
|
||||
}
|
||||
|
||||
func generateDocs(cmd *cobra.Command, dir string) {
|
||||
for _, c := range cmd.Commands() {
|
||||
if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() {
|
||||
continue
|
||||
}
|
||||
|
||||
generateDocs(c, dir)
|
||||
}
|
||||
|
||||
basename := strings.Replace(cmd.CommandPath(), " ", "-", -1) + ".md"
|
||||
filename := filepath.Join(dir, basename)
|
||||
f, err := os.Create(filename)
|
||||
checkErr(err)
|
||||
defer f.Close()
|
||||
generateMarkdown(cmd, f)
|
||||
}
|
||||
|
||||
func generateMarkdown(cmd *cobra.Command, w io.Writer) {
|
||||
cmd.InitDefaultHelpCmd()
|
||||
cmd.InitDefaultHelpFlag()
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
name := cmd.CommandPath()
|
||||
|
||||
short := cmd.Short
|
||||
long := cmd.Long
|
||||
if len(long) == 0 {
|
||||
long = short
|
||||
}
|
||||
|
||||
buf.WriteString("---\ndescription: " + short + "\n---\n\n")
|
||||
buf.WriteString("# " + name + "\n\n")
|
||||
buf.WriteString("## Synopsis\n\n")
|
||||
buf.WriteString(long + "\n\n")
|
||||
|
||||
if cmd.Runnable() {
|
||||
buf.WriteString(fmt.Sprintf("```\n%s\n```\n\n", cmd.UseLine()))
|
||||
}
|
||||
|
||||
if len(cmd.Example) > 0 {
|
||||
buf.WriteString("## Examples\n\n")
|
||||
buf.WriteString(fmt.Sprintf("```\n%s\n```\n\n", cmd.Example))
|
||||
}
|
||||
|
||||
printOptions(buf, cmd, name)
|
||||
_, err := buf.WriteTo(w)
|
||||
checkErr(err)
|
||||
}
|
||||
|
||||
func printOptions(buf *bytes.Buffer, cmd *cobra.Command, name string) {
|
||||
flags := cmd.NonInheritedFlags()
|
||||
flags.SetOutput(buf)
|
||||
if flags.HasAvailableFlags() {
|
||||
buf.WriteString("## Options\n\n```\n")
|
||||
flags.PrintDefaults()
|
||||
buf.WriteString("```\n\n")
|
||||
}
|
||||
|
||||
parentFlags := cmd.InheritedFlags()
|
||||
parentFlags.SetOutput(buf)
|
||||
if parentFlags.HasAvailableFlags() {
|
||||
buf.WriteString("### Inherited\n\n```\n")
|
||||
parentFlags.PrintDefaults()
|
||||
buf.WriteString("```\n")
|
||||
}
|
||||
}
|
||||
30
cmd/import.go
Normal file
30
cmd/import.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/filebrowser/filebrowser/v2/storage/bolt/importer"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(importCmd)
|
||||
|
||||
importCmd.Flags().String("old.database", "", "")
|
||||
importCmd.Flags().String("old.config", "", "")
|
||||
importCmd.MarkFlagRequired("old.database")
|
||||
}
|
||||
|
||||
var importCmd = &cobra.Command{
|
||||
Use: "import",
|
||||
Short: "Imports an old configuration",
|
||||
Long: `Imports an old configuration. This command DOES NOT
|
||||
import share links because they are incompatible with
|
||||
this version.`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
oldDB := mustGetString(cmd, "old.database")
|
||||
oldConf := mustGetString(cmd, "old.config")
|
||||
|
||||
err := importer.Import(oldDB, oldConf, databasePath)
|
||||
checkErr(err)
|
||||
},
|
||||
}
|
||||
203
cmd/root.go
Normal file
203
cmd/root.go
Normal file
@@ -0,0 +1,203 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/asdine/storm"
|
||||
"github.com/filebrowser/filebrowser/v2/auth"
|
||||
"github.com/filebrowser/filebrowser/v2/settings"
|
||||
"github.com/filebrowser/filebrowser/v2/storage"
|
||||
"github.com/filebrowser/filebrowser/v2/users"
|
||||
|
||||
fbhttp "github.com/filebrowser/filebrowser/v2/http"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
lumberjack "gopkg.in/natefinch/lumberjack.v2"
|
||||
)
|
||||
|
||||
var (
|
||||
databasePath string
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.PersistentFlags().StringVarP(&databasePath, "database", "d", "./filebrowser.db", "path to the database")
|
||||
|
||||
rootCmd.Flags().StringP("address", "a", "", "address to listen on (default comes from database)")
|
||||
rootCmd.Flags().StringP("log", "l", "", "log output (default comes from database)")
|
||||
rootCmd.Flags().IntP("port", "p", 0, "port to listen on (default comes from database)")
|
||||
rootCmd.Flags().StringP("cert", "c", "", "tls certificate (default comes from database)")
|
||||
rootCmd.Flags().StringP("key", "k", "", "tls key (default comes from database)")
|
||||
rootCmd.Flags().StringP("scope", "s", "", "scope for users")
|
||||
}
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
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
|
||||
web interface.
|
||||
|
||||
If you've never run File Browser, you will need to create the database.
|
||||
See 'filebrowser help config init' for more information.
|
||||
|
||||
This command is used to start up the server. By default it starts listening
|
||||
on localhost on a random port unless specified otherwise in the database or
|
||||
via flags.
|
||||
|
||||
Use the available flags to override the database/default options. These flags
|
||||
values won't be persisted to the database. To persist configuration to the database
|
||||
use the command 'filebrowser config set'.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if _, err := os.Stat(databasePath); os.IsNotExist(err) {
|
||||
quickSetup(cmd)
|
||||
}
|
||||
|
||||
db := getDB()
|
||||
defer db.Close()
|
||||
st := getStorage(db)
|
||||
startServer(cmd, st)
|
||||
},
|
||||
}
|
||||
|
||||
func setupLogger(s *settings.Settings) {
|
||||
switch s.Log {
|
||||
case "stdout":
|
||||
log.SetOutput(os.Stdout)
|
||||
case "stderr":
|
||||
log.SetOutput(os.Stderr)
|
||||
case "":
|
||||
log.SetOutput(ioutil.Discard)
|
||||
default:
|
||||
log.SetOutput(&lumberjack.Logger{
|
||||
Filename: s.Log,
|
||||
MaxSize: 100,
|
||||
MaxAge: 14,
|
||||
MaxBackups: 10,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func serverVisitAndReplace(cmd *cobra.Command, s *settings.Settings) {
|
||||
cmd.Flags().Visit(func(flag *pflag.Flag) {
|
||||
switch flag.Name {
|
||||
case "log":
|
||||
s.Log = mustGetString(cmd, flag.Name)
|
||||
case "address":
|
||||
s.Server.Address = mustGetString(cmd, flag.Name)
|
||||
case "port":
|
||||
s.Server.Port = mustGetInt(cmd, flag.Name)
|
||||
case "cert":
|
||||
s.Server.TLSCert = mustGetString(cmd, flag.Name)
|
||||
case "key":
|
||||
s.Server.TLSKey = mustGetString(cmd, flag.Name)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func quickSetup(cmd *cobra.Command) {
|
||||
scope := mustGetString(cmd, "scope")
|
||||
if scope == "" {
|
||||
panic(errors.New("scope flag must be set for quick setup"))
|
||||
}
|
||||
|
||||
db, err := storm.Open(databasePath)
|
||||
checkErr(err)
|
||||
defer db.Close()
|
||||
|
||||
set := &settings.Settings{
|
||||
Key: generateRandomBytes(64), // 256 bit
|
||||
BaseURL: "",
|
||||
Log: "stderr",
|
||||
Signup: false,
|
||||
AuthMethod: auth.MethodJSONAuth,
|
||||
Server: settings.Server{
|
||||
Port: 0,
|
||||
Address: "127.0.0.1",
|
||||
TLSCert: mustGetString(cmd, "cert"),
|
||||
TLSKey: mustGetString(cmd, "key"),
|
||||
},
|
||||
Defaults: settings.UserDefaults{
|
||||
Scope: scope,
|
||||
Locale: "en",
|
||||
Perm: users.Permissions{
|
||||
Admin: false,
|
||||
Execute: true,
|
||||
Create: true,
|
||||
Rename: true,
|
||||
Modify: true,
|
||||
Delete: true,
|
||||
Share: true,
|
||||
Download: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
serverVisitAndReplace(cmd, set)
|
||||
st := getStorage(db)
|
||||
|
||||
err = st.Settings.Save(set)
|
||||
checkErr(err)
|
||||
|
||||
err = st.Auth.Save(&auth.JSONAuth{})
|
||||
checkErr(err)
|
||||
|
||||
password, err := users.HashPwd("admin")
|
||||
checkErr(err)
|
||||
|
||||
user := &users.User{
|
||||
Username: "admin",
|
||||
Password: password,
|
||||
LockPassword: false,
|
||||
}
|
||||
|
||||
set.Defaults.Apply(user)
|
||||
user.Perm.Admin = true
|
||||
|
||||
err = st.Users.Save(user)
|
||||
checkErr(err)
|
||||
}
|
||||
|
||||
func startServer(cmd *cobra.Command, st *storage.Storage) {
|
||||
settings, err := st.Settings.Get()
|
||||
checkErr(err)
|
||||
|
||||
serverVisitAndReplace(cmd, settings)
|
||||
setupLogger(settings)
|
||||
|
||||
handler, err := fbhttp.NewHandler(st)
|
||||
checkErr(err)
|
||||
|
||||
var listener net.Listener
|
||||
|
||||
if settings.Server.TLSKey != "" && settings.Server.TLSCert != "" {
|
||||
cer, err := tls.LoadX509KeyPair(settings.Server.TLSCert, settings.Server.TLSKey)
|
||||
checkErr(err)
|
||||
config := &tls.Config{Certificates: []tls.Certificate{cer}}
|
||||
listener, err = tls.Listen("tcp", settings.Server.Address+":"+strconv.Itoa(settings.Server.Port), config)
|
||||
checkErr(err)
|
||||
} else {
|
||||
listener, err = net.Listen("tcp", settings.Server.Address+":"+strconv.Itoa(settings.Server.Port))
|
||||
checkErr(err)
|
||||
}
|
||||
|
||||
log.Println("Listening on", listener.Addr().String())
|
||||
if err := http.Serve(listener, handler); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func generateRandomBytes(n int) []byte {
|
||||
b := make([]byte, n)
|
||||
_, err := rand.Read(b)
|
||||
checkErr(err)
|
||||
// Note that err == nil only if we read len(b) bytes.
|
||||
return b
|
||||
}
|
||||
38
cmd/rule_rm.go
Normal file
38
cmd/rule_rm.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/filebrowser/filebrowser/v2/settings"
|
||||
"github.com/filebrowser/filebrowser/v2/storage"
|
||||
"github.com/filebrowser/filebrowser/v2/users"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rulesCmd.AddCommand(rulesRmCommand)
|
||||
rulesRmCommand.Flags().Uint("index", 0, "index of rule to remove")
|
||||
rulesRmCommand.MarkFlagRequired("index")
|
||||
}
|
||||
|
||||
var rulesRmCommand = &cobra.Command{
|
||||
Use: "rm",
|
||||
Short: "Remove a global rule or user rule",
|
||||
Long: `Remove a global rule or user rule.`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
index := mustGetUint(cmd, "index")
|
||||
|
||||
user := func(u *users.User, st *storage.Storage) {
|
||||
u.Rules = append(u.Rules[:index], u.Rules[index+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:]...)
|
||||
err := st.Settings.Save(s)
|
||||
checkErr(err)
|
||||
}
|
||||
|
||||
runRules(cmd, user, global)
|
||||
},
|
||||
}
|
||||
91
cmd/rules.go
Normal file
91
cmd/rules.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/filebrowser/filebrowser/v2/rules"
|
||||
"github.com/filebrowser/filebrowser/v2/settings"
|
||||
"github.com/filebrowser/filebrowser/v2/storage"
|
||||
"github.com/filebrowser/filebrowser/v2/users"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(rulesCmd)
|
||||
rulesCmd.PersistentFlags().StringP("username", "u", "", "username of user to which the rules apply")
|
||||
rulesCmd.PersistentFlags().UintP("id", "i", 0, "id of user to which the rules apply")
|
||||
}
|
||||
|
||||
var rulesCmd = &cobra.Command{
|
||||
Use: "rules",
|
||||
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
|
||||
an user, otherwise it will be applied to the global set or
|
||||
rules.`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmd.Help()
|
||||
os.Exit(0)
|
||||
},
|
||||
}
|
||||
|
||||
func runRules(cmd *cobra.Command, users func(*users.User, *storage.Storage), global func(*settings.Settings, *storage.Storage)) {
|
||||
db := getDB()
|
||||
defer db.Close()
|
||||
st := getStorage(db)
|
||||
|
||||
id := getUserIdentifier(cmd)
|
||||
if id != nil {
|
||||
user, err := st.Users.Get(id)
|
||||
checkErr(err)
|
||||
|
||||
if users != nil {
|
||||
users(user, st)
|
||||
}
|
||||
|
||||
printRules(user.Rules, id)
|
||||
return
|
||||
}
|
||||
|
||||
settings, err := st.Settings.Get()
|
||||
checkErr(err)
|
||||
|
||||
if global != nil {
|
||||
global(settings, st)
|
||||
}
|
||||
|
||||
printRules(settings.Rules, id)
|
||||
}
|
||||
|
||||
func getUserIdentifier(cmd *cobra.Command) interface{} {
|
||||
id := mustGetUint(cmd, "id")
|
||||
username := mustGetString(cmd, "username")
|
||||
|
||||
if id != 0 {
|
||||
return id
|
||||
} else if username != "" {
|
||||
return username
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func printRules(rules []rules.Rule, id interface{}) {
|
||||
if id == nil {
|
||||
fmt.Printf("Global Rules:\n\n")
|
||||
} else {
|
||||
fmt.Printf("Rules for user %v:\n\n", id)
|
||||
}
|
||||
|
||||
for id, rule := range rules {
|
||||
fmt.Printf("(%d) ", id)
|
||||
if rule.Regex {
|
||||
fmt.Printf("Allow: %t\tRegex: %s\n", rule.Allow, rule.Regexp.Raw)
|
||||
} else {
|
||||
fmt.Printf("Allow: %t\tPath: %s\n", rule.Allow, rule.Path)
|
||||
}
|
||||
}
|
||||
}
|
||||
67
cmd/rules_add.go
Normal file
67
cmd/rules_add.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"regexp"
|
||||
|
||||
"github.com/filebrowser/filebrowser/v2/rules"
|
||||
"github.com/filebrowser/filebrowser/v2/settings"
|
||||
"github.com/filebrowser/filebrowser/v2/storage"
|
||||
"github.com/filebrowser/filebrowser/v2/users"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
var rulesAddCmd = &cobra.Command{
|
||||
Use: "add",
|
||||
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,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
allow := mustGetBool(cmd, "allow")
|
||||
path := mustGetString(cmd, "path")
|
||||
regex := mustGetString(cmd, "regex")
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
rule := rules.Rule{
|
||||
Allow: allow,
|
||||
Path: path,
|
||||
Regex: regex != "",
|
||||
Regexp: &rules.Regexp{
|
||||
Raw: regex,
|
||||
},
|
||||
}
|
||||
|
||||
user := func(u *users.User, st *storage.Storage) {
|
||||
u.Rules = append(u.Rules, rule)
|
||||
err := st.Users.Save(u)
|
||||
checkErr(err)
|
||||
}
|
||||
|
||||
global := func(s *settings.Settings, st *storage.Storage) {
|
||||
s.Rules = append(s.Rules, rule)
|
||||
err := st.Settings.Save(s)
|
||||
checkErr(err)
|
||||
}
|
||||
|
||||
runRules(cmd, user, global)
|
||||
},
|
||||
}
|
||||
19
cmd/rules_ls.go
Normal file
19
cmd/rules_ls.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rulesCmd.AddCommand(rulesLsCommand)
|
||||
}
|
||||
|
||||
var rulesLsCommand = &cobra.Command{
|
||||
Use: "ls",
|
||||
Short: "List global rules or user specific rules",
|
||||
Long: `List global rules or user specific rules.`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
runRules(cmd, nil, nil)
|
||||
},
|
||||
}
|
||||
134
cmd/users.go
Normal file
134
cmd/users.go
Normal file
@@ -0,0 +1,134 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/filebrowser/filebrowser/v2/settings"
|
||||
"github.com/filebrowser/filebrowser/v2/users"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(usersCmd)
|
||||
}
|
||||
|
||||
var usersCmd = &cobra.Command{
|
||||
Use: "users",
|
||||
Short: "Users management utility",
|
||||
Long: `Users management utility.`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmd.Help()
|
||||
os.Exit(0)
|
||||
},
|
||||
}
|
||||
|
||||
func printUsers(users []*users.User) {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprintln(w, "ID\tUsername\tScope\tLocale\tV. Mode\tAdmin\tExecute\tCreate\tRename\tModify\tDelete\tShare\tDownload\tPwd Lock")
|
||||
|
||||
for _, user := range users {
|
||||
fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t\n",
|
||||
user.ID,
|
||||
user.Username,
|
||||
user.Scope,
|
||||
user.Locale,
|
||||
user.ViewMode,
|
||||
user.Perm.Admin,
|
||||
user.Perm.Execute,
|
||||
user.Perm.Create,
|
||||
user.Perm.Rename,
|
||||
user.Perm.Modify,
|
||||
user.Perm.Delete,
|
||||
user.Perm.Share,
|
||||
user.Perm.Download,
|
||||
user.LockPassword,
|
||||
)
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func addUserFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().Bool("perm.admin", false, "admin perm for users")
|
||||
cmd.Flags().Bool("perm.execute", true, "execute perm for users")
|
||||
cmd.Flags().Bool("perm.create", true, "create perm for users")
|
||||
cmd.Flags().Bool("perm.rename", true, "rename perm for users")
|
||||
cmd.Flags().Bool("perm.modify", true, "modify perm for users")
|
||||
cmd.Flags().Bool("perm.delete", true, "delete perm for users")
|
||||
cmd.Flags().Bool("perm.share", true, "share perm for users")
|
||||
cmd.Flags().Bool("perm.download", true, "download perm for users")
|
||||
cmd.Flags().String("sorting.by", "name", "sorting mode (name, size or modified)")
|
||||
cmd.Flags().Bool("sorting.asc", false, "sorting by ascending order")
|
||||
cmd.Flags().Bool("lockPassword", false, "lock password")
|
||||
cmd.Flags().StringSlice("commands", nil, "a list of the commands a user can execute")
|
||||
cmd.Flags().String("scope", "", "scope for users")
|
||||
cmd.Flags().String("locale", "en", "locale for users")
|
||||
cmd.Flags().String("viewMode", string(users.ListViewMode), "view mode for users")
|
||||
}
|
||||
|
||||
func getViewMode(cmd *cobra.Command) users.ViewMode {
|
||||
viewMode := users.ViewMode(mustGetString(cmd, "viewMode"))
|
||||
if viewMode != users.ListViewMode && viewMode != users.MosaicViewMode {
|
||||
checkErr(errors.New("view mode must be \"" + string(users.ListViewMode) + "\" or \"" + string(users.MosaicViewMode) + "\""))
|
||||
}
|
||||
return viewMode
|
||||
}
|
||||
|
||||
func getUserDefaults(cmd *cobra.Command, defaults *settings.UserDefaults, all bool) {
|
||||
visit := func(flag *pflag.Flag) {
|
||||
switch flag.Name {
|
||||
case "scope":
|
||||
defaults.Scope = mustGetString(cmd, "scope")
|
||||
case "locale":
|
||||
defaults.Locale = mustGetString(cmd, "locale")
|
||||
case "viewMode":
|
||||
defaults.ViewMode = getViewMode(cmd)
|
||||
case "perm.admin":
|
||||
defaults.Perm.Admin = mustGetBool(cmd, "perm.admin")
|
||||
case "perm.execute":
|
||||
defaults.Perm.Execute = mustGetBool(cmd, "perm.execute")
|
||||
case "perm.create":
|
||||
defaults.Perm.Create = mustGetBool(cmd, "perm.create")
|
||||
case "perm.rename":
|
||||
defaults.Perm.Rename = mustGetBool(cmd, "perm.rename")
|
||||
case "perm.modify":
|
||||
defaults.Perm.Modify = mustGetBool(cmd, "perm.modify")
|
||||
case "perm.delete":
|
||||
defaults.Perm.Delete = mustGetBool(cmd, "perm.delete")
|
||||
case "perm.share":
|
||||
defaults.Perm.Share = mustGetBool(cmd, "perm.share")
|
||||
case "perm.download":
|
||||
defaults.Perm.Download = mustGetBool(cmd, "perm.download")
|
||||
case "commands":
|
||||
commands, err := cmd.Flags().GetStringSlice("commands")
|
||||
checkErr(err)
|
||||
defaults.Commands = commands
|
||||
case "sorting.by":
|
||||
defaults.Sorting.By = mustGetString(cmd, "sorting.by")
|
||||
case "sorting.asc":
|
||||
defaults.Sorting.Asc = mustGetBool(cmd, "sorting.asc")
|
||||
}
|
||||
}
|
||||
|
||||
if all {
|
||||
cmd.Flags().VisitAll(visit)
|
||||
} else {
|
||||
cmd.Flags().Visit(visit)
|
||||
}
|
||||
}
|
||||
57
cmd/users_find.go
Normal file
57
cmd/users_find.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/filebrowser/filebrowser/v2/users"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
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",
|
||||
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,
|
||||
Run: findUsers,
|
||||
}
|
||||
|
||||
var usersLsCmd = &cobra.Command{
|
||||
Use: "ls",
|
||||
Short: "List all users.",
|
||||
Args: cobra.NoArgs,
|
||||
Run: findUsers,
|
||||
}
|
||||
|
||||
var findUsers = func(cmd *cobra.Command, args []string) {
|
||||
db := getDB()
|
||||
defer db.Close()
|
||||
st := getStorage(db)
|
||||
|
||||
username, _ := cmd.Flags().GetString("username")
|
||||
id, _ := cmd.Flags().GetUint("id")
|
||||
|
||||
var err error
|
||||
var list []*users.User
|
||||
var user *users.User
|
||||
|
||||
if username != "" {
|
||||
user, err = st.Users.Get(username)
|
||||
} else if id != 0 {
|
||||
user, err = st.Users.Get(id)
|
||||
} else {
|
||||
list, err = st.Users.Gets()
|
||||
}
|
||||
|
||||
checkErr(err)
|
||||
|
||||
if user != nil {
|
||||
list = []*users.User{user}
|
||||
}
|
||||
|
||||
printUsers(list)
|
||||
}
|
||||
47
cmd/users_new.go
Normal file
47
cmd/users_new.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/filebrowser/filebrowser/v2/users"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
var usersNewCmd = &cobra.Command{
|
||||
Use: "new",
|
||||
Short: "Create a new user",
|
||||
Long: `Create a new user and add it to the database.`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
db := getDB()
|
||||
defer db.Close()
|
||||
st := getStorage(db)
|
||||
|
||||
s, err := st.Settings.Get()
|
||||
checkErr(err)
|
||||
getUserDefaults(cmd, &s.Defaults, false)
|
||||
|
||||
password, _ := cmd.Flags().GetString("password")
|
||||
password, err = users.HashPwd(password)
|
||||
checkErr(err)
|
||||
|
||||
user := &users.User{
|
||||
Username: mustGetString(cmd, "username"),
|
||||
Password: password,
|
||||
LockPassword: mustGetBool(cmd, "lockPassword"),
|
||||
}
|
||||
|
||||
s.Defaults.Apply(user)
|
||||
err = st.Users.Save(user)
|
||||
checkErr(err)
|
||||
printUsers([]*users.User{user})
|
||||
},
|
||||
}
|
||||
39
cmd/users_rm.go
Normal file
39
cmd/users_rm.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
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",
|
||||
Short: "Delete a user by username or id",
|
||||
Long: `Delete a user by username or id`,
|
||||
Args: usernameOrIDRequired,
|
||||
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")
|
||||
|
||||
var err error
|
||||
|
||||
if username != "" {
|
||||
err = st.Users.Delete(username)
|
||||
} else {
|
||||
err = st.Users.Delete(id)
|
||||
}
|
||||
|
||||
checkErr(err)
|
||||
fmt.Println("user deleted successfully")
|
||||
},
|
||||
}
|
||||
74
cmd/users_update.go
Normal file
74
cmd/users_update.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/filebrowser/filebrowser/v2/settings"
|
||||
"github.com/filebrowser/filebrowser/v2/users"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
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")
|
||||
addUserFlags(usersUpdateCmd)
|
||||
}
|
||||
|
||||
var usersUpdateCmd = &cobra.Command{
|
||||
Use: "update",
|
||||
Short: "Updates an existing user",
|
||||
Long: `Updates an existing user. Set the flags for the
|
||||
options you want to change.`,
|
||||
Args: usernameOrIDRequired,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
db := getDB()
|
||||
defer db.Close()
|
||||
st := getStorage(db)
|
||||
|
||||
id, _ := cmd.Flags().GetUint("id")
|
||||
username := mustGetString(cmd, "username")
|
||||
password := mustGetString(cmd, "password")
|
||||
|
||||
var user *users.User
|
||||
var err error
|
||||
|
||||
if id != 0 {
|
||||
user, err = st.Users.Get(id)
|
||||
} else {
|
||||
user, err = st.Users.Get(username)
|
||||
}
|
||||
|
||||
checkErr(err)
|
||||
|
||||
defaults := settings.UserDefaults{
|
||||
Scope: user.Scope,
|
||||
Locale: user.Locale,
|
||||
ViewMode: user.ViewMode,
|
||||
Perm: user.Perm,
|
||||
Sorting: user.Sorting,
|
||||
Commands: user.Commands,
|
||||
}
|
||||
getUserDefaults(cmd, &defaults, false)
|
||||
user.Scope = defaults.Scope
|
||||
user.Locale = defaults.Locale
|
||||
user.ViewMode = defaults.ViewMode
|
||||
user.Perm = defaults.Perm
|
||||
user.Commands = defaults.Commands
|
||||
user.Sorting = defaults.Sorting
|
||||
user.LockPassword = mustGetBool(cmd, "lockPassword")
|
||||
|
||||
if user.Username != username && username != "" {
|
||||
user.Username = username
|
||||
}
|
||||
|
||||
if password != "" {
|
||||
user.Password, err = users.HashPwd(password)
|
||||
checkErr(err)
|
||||
}
|
||||
|
||||
err = st.Users.Update(user)
|
||||
checkErr(err)
|
||||
printUsers([]*users.User{user})
|
||||
},
|
||||
}
|
||||
55
cmd/utils.go
Normal file
55
cmd/utils.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
"github.com/asdine/storm"
|
||||
"github.com/filebrowser/filebrowser/v2/storage"
|
||||
"github.com/filebrowser/filebrowser/v2/storage/bolt"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func checkErr(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func mustGetString(cmd *cobra.Command, flag string) string {
|
||||
s, err := cmd.Flags().GetString(flag)
|
||||
checkErr(err)
|
||||
return s
|
||||
}
|
||||
|
||||
func mustGetBool(cmd *cobra.Command, flag string) bool {
|
||||
b, err := cmd.Flags().GetBool(flag)
|
||||
checkErr(err)
|
||||
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)
|
||||
return b
|
||||
}
|
||||
|
||||
func getDB() *storm.DB {
|
||||
if _, err := os.Stat(databasePath); err != nil {
|
||||
panic(errors.New(databasePath + " does not exist. Please run 'filebrowser init' first."))
|
||||
}
|
||||
|
||||
db, err := storm.Open(databasePath)
|
||||
checkErr(err)
|
||||
return db
|
||||
}
|
||||
|
||||
func getStorage(db *storm.DB) *storage.Storage {
|
||||
return bolt.NewStorage(db)
|
||||
}
|
||||
20
cmd/version.go
Normal file
20
cmd/version.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/filebrowser/filebrowser/v2/version"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(versionCmd)
|
||||
}
|
||||
|
||||
var versionCmd = &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Print the version number",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println("File Browser Version " + version.Version)
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user