From 58d0f8aec79a3c947f970459d5a3fd7ecd6d2c05 Mon Sep 17 00:00:00 2001 From: Theo S Schult <theo.sschult@gmail.com> Date: Thu, 6 Feb 2025 21:47:11 -0300 Subject: [PATCH] Implement mod subcommand inteface --- .gitignore | 1 + cmd/user/create.go | 6 ++ cmd/user/delete.go | 2 +- cmd/user/mod.go | 145 ++++++++++++++++++++++++++++++++++++++++++++- model/user.go | 8 ++- 5 files changed, 157 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 2d0b03e..97caac8 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ useradm +build.sh diff --git a/cmd/user/create.go b/cmd/user/create.go index 455b98e..7022dee 100644 --- a/cmd/user/create.go +++ b/cmd/user/create.go @@ -27,6 +27,7 @@ func init() { CreateCmd.Flags().StringP("shell", "s", "/bin/bash", "Full path to shell ") CreateCmd.Flags().StringP("homedir", "d", "", "Home directory path (/home/group/login if empty)") CreateCmd.Flags().StringP("password", "p", "", "User password (auto-generated if empty)") + CreateCmd.Flags().StringP("status", "a", "Free", "User status (Blocked/Free)") // Required Flags CreateCmd.MarkFlagRequired("name") @@ -77,6 +78,10 @@ func createUserFunc(cmd *cobra.Command, args []string) error { if err != nil { return err } + userStatus, err := cmd.Flags().GetString("status") + if err != nil { + return err + } user := model.User{ Name: userName, @@ -88,6 +93,7 @@ func createUserFunc(cmd *cobra.Command, args []string) error { Shell: userShell, Homedir: userHomedir, Password: ifThenElse(userPassword != "", "[set]", "[auto-generate]"), + Status: userStatus, } fmt.Println(user.ToString()) diff --git a/cmd/user/delete.go b/cmd/user/delete.go index a55844e..2777308 100644 --- a/cmd/user/delete.go +++ b/cmd/user/delete.go @@ -4,5 +4,5 @@ import "github.com/spf13/cobra" var DeleteCmd = &cobra.Command{ Use: "delete", - Short: "Deleta a user", + Short: "Delete a user", } diff --git a/cmd/user/mod.go b/cmd/user/mod.go index 66b2a59..5dc5b03 100644 --- a/cmd/user/mod.go +++ b/cmd/user/mod.go @@ -1,8 +1,151 @@ package user -import "github.com/spf13/cobra" +import ( + "os" + "fmt" + "bufio" + "errors" + "strings" + "crypto/rand" + + "github.com/spf13/cobra" + "gitlab.c3sl.ufpr.br/tss24/useradm/model" +) var ModCmd = &cobra.Command{ Use: "mod", Short: "Modify user information", + RunE: modifyUserFunc, +} + +func init() { + ModCmd.Flags().StringP("grr", "r", "", "New user GRR") + ModCmd.Flags().StringP("shell", "s", "", "New user shell") + ModCmd.Flags().StringP("login", "l", "", "User login name") + ModCmd.Flags().StringP("homedir", "d", "", "New user home") + ModCmd.Flags().BoolP ("unblock", "u", false, "Unblocks the user") + ModCmd.Flags().StringP("group", "g", "", "New user initial group") + ModCmd.Flags().StringP("path", "w", "", "Create Webdir, path/login") + ModCmd.Flags().StringP("name", "n", "", "New user full name (use quotes for spaces)") + ModCmd.Flags().StringP("password", "p", "", "New password in plain text (use \"auto\" to autogenerate)") + ModCmd.Flags().BoolP ("block", "b", false, "Block the user (changes the password and sets their shell to /bin/false)") + + ModCmd.MarkFlagRequired("login") + + ModCmd.Flags().BoolP("confirm", "y", false, "Skip confirmation prompt") +} + +func modifyUserFunc(cmd *cobra.Command, args []string) error { + confirm, err := cmd.Flags().GetBool("confirm") + if err != nil { + return err + } + block, err := cmd.Flags().GetBool("block") + if err != nil { + return err + } + unblock, err := cmd.Flags().GetBool("unblock") + if err != nil { + return err + } + userNameNew, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + userGroupNew, err := cmd.Flags().GetString("group") + if err != nil { + return err + } + userGRRNew, err := cmd.Flags().GetString("grr") + if err != nil { + return err + } + userPathNew, err := cmd.Flags().GetString("path") + if err != nil { + return err + } + userLogin, err := cmd.Flags().GetString("login") + if err != nil { + return err + } + userShellNew, err := cmd.Flags().GetString("shell") + if err != nil { + return err + } + userHomedirNew, err := cmd.Flags().GetString("homedir") + if err != nil { + return err + } + userPasswordNew, err := cmd.Flags().GetString("password") + if err != nil { + return err + } + if block && unblock { + return errors.New("Can't block and unblock at the same time!\n") + } + + var userStatusNew string + if block { + userShellNew = "/bin/false" + userStatusNew = "Blocked!" + userPasswordNew = "auto" + } else if unblock { + userShellNew = "/bin/bash" + userStatusNew = "Free!" + userPasswordNew = "auto" + } + + userMod := model.User{ + Name: userNameNew, + Group: userGroupNew, + GRR: userGRRNew, + Path: userPathNew, + Login: userLogin, + Shell: userShellNew, + Homedir: userHomedirNew, + Password: userPasswordNew, + Status: userStatusNew, + } + + if cmd.Flags().Changed("password") || block || unblock { + if userPasswordNew == "auto" { + userPasswordNew = generatePassword() + userMod.Password = "[auto-generated]" + } else { + userMod.Password = "[explicitly set]" + } + } else { + userMod.Password = "[unchanged]" + } + + fmt.Println(userMod.ToString()) + + if !confirm { + fmt.Print("Proceed with user update? [y/N] ") + reader := bufio.NewReader(os.Stdin) + response, _ := reader.ReadString('\n') + if strings.TrimSpace(strings.ToLower(response)) != "y" { + fmt.Fprintln(os.Stderr, "Aborted.") + os.Exit(1) + } + } + + fmt.Println("Done!") + + fmt.Println(userPasswordNew) + + return nil +} + +func generatePassword() string { + const charset = "@*()=+[];,.?123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ" + b := make([]byte, 20) + if _, err := rand.Read(b); err != nil { + panic(err) + } + for i := range b { + b[i] = charset[int(b[i])%len(charset)] + } + return string(b) } + diff --git a/model/user.go b/model/user.go index 0036ff1..116f8e9 100644 --- a/model/user.go +++ b/model/user.go @@ -4,12 +4,13 @@ import "fmt" type User struct { GRR string - Ltype string Path string Name string + Ltype string Login string Group string Shell string + Status string Homedir string Password string } @@ -23,6 +24,7 @@ func (u *User) ToString() string { Shell: %s HomeDir: %s Password: %s - WebPath: %s`, - u.Name, u.Login, u.Ltype, u.Group, u.Shell, u.Homedir, u.Password, u.Path) + WebPath: %s + Status: %s`, + u.Name, u.Login, u.Ltype, u.Group, u.Shell, u.Homedir, u.Password, u.Path, u.Status) } -- GitLab