diff --git a/cmd/rule_rm.go b/cmd/rule_rm.go new file mode 100644 index 00000000..8b1dda1a --- /dev/null +++ b/cmd/rule_rm.go @@ -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) + }, +} diff --git a/cmd/rules.go b/cmd/rules.go new file mode 100644 index 00000000..473a8572 --- /dev/null +++ b/cmd/rules.go @@ -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) + } + } +} diff --git a/cmd/rules_add.go b/cmd/rules_add.go new file mode 100644 index 00000000..8e982a95 --- /dev/null +++ b/cmd/rules_add.go @@ -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) + }, +} diff --git a/cmd/rules_ls.go b/cmd/rules_ls.go new file mode 100644 index 00000000..72cb9431 --- /dev/null +++ b/cmd/rules_ls.go @@ -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) + }, +} diff --git a/cmd/utils.go b/cmd/utils.go index e943c2a7..8b2520dd 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -34,6 +34,12 @@ func mustGetInt(cmd *cobra.Command, flag string) int { 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."))