diff --git a/galenectl/galenectl.go b/galenectl/galenectl.go index 2685516..05cfd2d 100644 --- a/galenectl/galenectl.go +++ b/galenectl/galenectl.go @@ -241,10 +241,7 @@ func setUsage(cmd *flag.FlagSet, cmdname string, format string, args ...any) { func hashPasswordCmd(cmdname string, args []string) { var algorithm string - var iterations int - var cost int - var length int - var saltlen int + var iterations, cost, length, saltlen int cmd := flag.NewFlagSet(cmdname, flag.ExitOnError) setUsage(cmd, cmdname, @@ -311,7 +308,7 @@ func putJSON(url string, value any, overwrite bool) error { } defer resp.Body.Close() if resp.StatusCode >= 300 { - return fmt.Errorf("%v %v", resp.StatusCode, resp.Status) + return errors.New(resp.Status) } return nil } @@ -383,19 +380,19 @@ func deleteValue(url string) error { } func setPasswordCmd(cmdname string, args []string) { - var groupname string + var groupname, username string + var wildcard bool var algorithm string - var iterations int - var cost int - var length int - var saltlen int + var iterations, cost, length, saltlen int cmd := flag.NewFlagSet(cmdname, flag.ExitOnError) setUsage(cmd, cmdname, - "%v [option...] %v [option...] username password\n", + "%v [option...] %v [option...] password\n", os.Args[0], cmdname, ) cmd.StringVar(&groupname, "group", "", "group `name`") + cmd.StringVar(&username, "user", "", "user `name`") + cmd.BoolVar(&wildcard, "wildcard", false, "set wildcard user's password") cmd.StringVar(&algorithm, "type", "pbkdf2", "password `type`") cmd.IntVar(&iterations, "iterations", 4096, @@ -406,88 +403,132 @@ func setPasswordCmd(cmdname string, args []string) { cmd.IntVar(&saltlen, "salt", 8, "salt `length` (pbkdf2)") cmd.Parse(args) - if cmd.NArg() != 2 { + if cmd.NArg() != 1 { cmd.Usage() os.Exit(1) } if groupname == "" { - fmt.Fprintf(cmd.Output(), "option \"-group\" is mandatory") + fmt.Fprintf(cmd.Output(), + "Option \"-group\" is required\n") + os.Exit(1) + } + + if wildcard != (username == "") { + fmt.Fprintf(cmd.Output(), + "Exactly one of \"-user\" and \"-wildcard\" "+ + "is required\n") os.Exit(1) } pw, err := makePassword( - cmd.Args()[1], + cmd.Args()[0], algorithm, iterations, length, saltlen, cost, ) if err != nil { log.Fatalf("Make password: %v", err) } - url, err := url.JoinPath( - serverURL, "/galene-api/v0/.groups", groupname, - ".users", cmd.Args()[0], ".password", - ) + var u string + if wildcard { + u, err = url.JoinPath( + serverURL, "/galene-api/v0/.groups", groupname, + ".wildcard-user/.password", + ) + } else { + u, err = url.JoinPath( + serverURL, "/galene-api/v0/.groups", groupname, + ".users", username, ".password", + ) + } if err != nil { log.Fatalf("Build URL: %v", err) } - err = putJSON(url, pw, true) + err = putJSON(u, pw, true) if err != nil { log.Fatalf("Set password: %v", err) } } func deletePasswordCmd(cmdname string, args []string) { - var groupname string + var groupname, username string + var wildcard bool cmd := flag.NewFlagSet(cmdname, flag.ExitOnError) setUsage(cmd, cmdname, - "%v [option...] %v [option...] username\n", + "%v [option...] %v [option...]\n", os.Args[0], cmdname, ) cmd.StringVar(&groupname, "group", "", "group `name`") + cmd.StringVar(&username, "user", "", "user `name`") + cmd.BoolVar(&wildcard, "wildcard", false, "set wildcard user's password") cmd.Parse(args) - if cmd.NArg() != 1 { + if cmd.NArg() != 0 { cmd.Usage() os.Exit(1) } if groupname == "" { - fmt.Fprintf(cmd.Output(), "option \"-group\" is mandatory") + fmt.Fprintf(cmd.Output(), + "Option \"-group\" is required\n") os.Exit(1) } - url, err := url.JoinPath( - serverURL, "/galene-api/v0/.groups", groupname, - ".users", cmd.Args()[0], ".password", - ) + if wildcard != (username == "") { + fmt.Fprintf(cmd.Output(), + "Exactly one of \"-user\" and \"-wildcard\" "+ + "is required\n") + os.Exit(1) + } + + var u string + var err error + if wildcard { + u, err = url.JoinPath( + serverURL, "/galene-api/v0/.groups", groupname, + ".wildcard-user/.password", + ) + } else { + u, err = url.JoinPath( + serverURL, "/galene-api/v0/.groups", groupname, + ".users", username, ".password", + ) + } if err != nil { log.Fatalf("Build URL: %v", err) } - err = deleteValue(url) + err = deleteValue(u) if err != nil { log.Fatalf("Delete password: %v", err) } } func createGroupCmd(cmdname string, args []string) { + var groupname string cmd := flag.NewFlagSet(cmdname, flag.ExitOnError) setUsage(cmd, cmdname, - "%v [option...] %v [option...] group\n", + "%v [option...] %v [option...]\n", os.Args[0], cmdname, ) + cmd.StringVar(&groupname, "group", "", "group `name`") cmd.Parse(args) - if cmd.NArg() != 1 { + if cmd.NArg() != 0 { cmd.Usage() os.Exit(1) } + if groupname == "" { + fmt.Fprintf(cmd.Output(), + "Option \"-group\" is required\n") + os.Exit(1) + } + url, err := url.JoinPath( - serverURL, "/galene-api/v0/.groups", cmd.Args()[0], + serverURL, "/galene-api/v0/.groups", groupname, ) if err != nil { log.Fatalf("Build URL: %v", err) @@ -500,20 +541,28 @@ func createGroupCmd(cmdname string, args []string) { } func deleteGroupCmd(cmdname string, args []string) { + var groupname string cmd := flag.NewFlagSet(cmdname, flag.ExitOnError) setUsage(cmd, cmdname, - "%v [option...] %v [option...] group\n", + "%v [option...] %v [option...]\n", os.Args[0], cmdname, ) + cmd.StringVar(&groupname, "group", "", "group `name`") cmd.Parse(args) - if cmd.NArg() != 1 { + if cmd.NArg() != 0 { cmd.Usage() os.Exit(1) } + if groupname == "" { + fmt.Fprintf(cmd.Output(), + "Option \"-group\" is required\n") + os.Exit(1) + } + url, err := url.JoinPath( - serverURL, "/galene-api/v0/.groups", cmd.Args()[0], + serverURL, "/galene-api/v0/.groups", groupname, ) if err != nil { log.Fatalf("Build URL: %v", err) @@ -542,7 +591,8 @@ func parsePermissions(p string) (any, error) { } func createUserCmd(cmdname string, args []string) { - var groupname string + var groupname, username string + var wildcard bool var permissions string cmd := flag.NewFlagSet(cmdname, flag.ExitOnError) setUsage(cmd, cmdname, @@ -550,68 +600,99 @@ func createUserCmd(cmdname string, args []string) { os.Args[0], cmdname, ) cmd.StringVar(&groupname, "group", "", "group") + cmd.StringVar(&username, "user", "", "user `name`") + cmd.BoolVar(&wildcard, "wildcard", false, "create the wildcard user") cmd.StringVar(&permissions, "permissions", "present", "permissions") cmd.Parse(args) - if cmd.NArg() != 1 { + if cmd.NArg() != 0 { cmd.Usage() os.Exit(1) } + if groupname == "" { + fmt.Fprintf(cmd.Output(), + "Option \"-group\" is required\n") + os.Exit(1) + } + + if wildcard != (username == "") { + fmt.Fprintf(cmd.Output(), + "Exactly one of \"-user\" and \"-wildcard\" "+ + "is required\n") + os.Exit(1) + } + perms, err := parsePermissions(permissions) if err != nil { log.Fatalf("Parse permissions: %v", err) } - url, err := url.JoinPath( - serverURL, "/galene-api/v0/.groups", groupname, - ".users", cmd.Args()[0], - ) + var u string + if wildcard { + u, err = url.JoinPath( + serverURL, "/galene-api/v0/.groups", groupname, + ".wildcard-user", + ) + } else { + u, err = url.JoinPath( + serverURL, "/galene-api/v0/.groups", groupname, + ".users", username, + ) + } if err != nil { log.Fatalf("Build URL: %v", err) } dict := map[string]any{"permissions": perms} - err = putJSON(url, dict, false) + err = putJSON(u, dict, false) if err != nil { log.Fatalf("Create user: %v", err) } } func updateUserCmd(cmdname string, args []string) { - var groupname string + var groupname, username string + var wildcard bool var permissions string cmd := flag.NewFlagSet(cmdname, flag.ExitOnError) setUsage(cmd, cmdname, - "%v [option...] %v [option...] username\n", + "%v [option...] %v [option...]\n", os.Args[0], cmdname, ) cmd.StringVar(&groupname, "group", "", "group `name`") + cmd.StringVar(&username, "user", "", "user `name`") + cmd.BoolVar(&wildcard, "wildcard", false, "update the wildcard user") cmd.StringVar(&permissions, "permissions", "", "permissions") cmd.Parse(args) - if cmd.NArg() != 1 { + if cmd.NArg() != 0 { cmd.Usage() os.Exit(1) } - if permissions == "" { - log.Fatalf("Nothing to do!") - } perms, err := parsePermissions(permissions) if err != nil { log.Fatalf("Parse permissions: %v", err) } - url, err := url.JoinPath( - serverURL, "/galene-api/v0/.groups", groupname, - ".users", cmd.Args()[0], - ) + var u string + if wildcard { + u, err = url.JoinPath( + serverURL, "/galene-api/v0/.groups", groupname, + ".wildcard-user", + ) + } else { + u, err = url.JoinPath( + serverURL, "/galene-api/v0/.groups", groupname, + ".users", username, + ) + } if err != nil { log.Fatalf("Build URL: %v", err) } - err = updateJSON(url, func(m map[string]any) map[string]any { + err = updateJSON(u, func(m map[string]any) map[string]any { m["permissions"] = perms return m }) @@ -622,33 +703,53 @@ func updateUserCmd(cmdname string, args []string) { } func deleteUserCmd(cmdname string, args []string) { - var groupname string + var groupname, username string + var wildcard bool cmd := flag.NewFlagSet(cmdname, flag.ExitOnError) - setUsage(cmd, cmdname, "%v [option...] %v [option...] username\n", + setUsage(cmd, cmdname, "%v [option...] %v [option...]\n", os.Args[0], cmdname, ) cmd.StringVar(&groupname, "group", "", "group `name`") + cmd.StringVar(&username, "user", "", "user `name`") + cmd.BoolVar(&wildcard, "wildcard", false, "delete the wildcard user") cmd.Parse(args) - if cmd.NArg() != 1 { + if cmd.NArg() != 0 { cmd.Usage() os.Exit(1) } if groupname == "" { - fmt.Fprintf(cmd.Output(), "option \"-group\" is mandatory") + fmt.Fprintf(cmd.Output(), + "Option \"-group\" is required\n") os.Exit(1) } - url, err := url.JoinPath( - serverURL, "/galene-api/v0/.groups", groupname, - ".users", cmd.Args()[0], - ) + if wildcard != (username == "") { + fmt.Fprintf(cmd.Output(), + "Exactly one of \"-user\" and \"-wildcard\" "+ + "is required\n") + os.Exit(1) + } + + var u string + var err error + if wildcard { + u, err = url.JoinPath( + serverURL, "/galene-api/v0/.groups", groupname, + ".wildcard-user", + ) + } else { + u, err = url.JoinPath( + serverURL, "/galene-api/v0/.groups", groupname, + ".users", username, + ) + } if err != nil { log.Fatalf("Build URL: %v", err) } - err = deleteValue(url) + err = deleteValue(u) if err != nil { log.Fatalf("Delete user: %v", err) }