From 403787e56c7dad6a063524c047170c0b842cee8c Mon Sep 17 00:00:00 2001 From: Stavros Date: Wed, 22 Jan 2025 16:05:01 +0200 Subject: [PATCH] feat: verify user cmd --- cmd/user/{subcommands => create}/create.go | 6 +- cmd/user/user.go | 6 +- cmd/user/verify/verify.go | 96 ++++++++++++++++++++++ 3 files changed, 104 insertions(+), 4 deletions(-) rename cmd/user/{subcommands => create}/create.go (87%) create mode 100644 cmd/user/verify/verify.go diff --git a/cmd/user/subcommands/create.go b/cmd/user/create/create.go similarity index 87% rename from cmd/user/subcommands/create.go rename to cmd/user/create/create.go index 23001ae..d250cf3 100644 --- a/cmd/user/subcommands/create.go +++ b/cmd/user/create/create.go @@ -1,4 +1,4 @@ -package subcommands +package create import ( "errors" @@ -37,7 +37,7 @@ var CreateCmd = &cobra.Command{ } return nil })), - huh.NewConfirm().Title("Format the output for docker?").Value(&docker).Affirmative("Yes").Negative("No"), + huh.NewSelect[bool]().Title("Format the output for docker?").Options(huh.NewOption("Yes", true), huh.NewOption("No", false)).Value(&docker), ), ) @@ -56,6 +56,8 @@ var CreateCmd = &cobra.Command{ os.Exit(1) } + log.Info().Str("username", username).Str("password", password).Bool("docker", docker).Msg("Creating user") + passwordByte, passwordErr := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if passwordErr != nil { diff --git a/cmd/user/user.go b/cmd/user/user.go index 1b35a95..b35328d 100644 --- a/cmd/user/user.go +++ b/cmd/user/user.go @@ -1,7 +1,8 @@ package cmd import ( - "tinyauth/cmd/user/subcommands" + "tinyauth/cmd/user/create" + "tinyauth/cmd/user/verify" "github.com/spf13/cobra" ) @@ -12,6 +13,7 @@ func UserCmd() *cobra.Command { Short: "User utilities", Long: `Utilities for creating and verifying tinyauth compatible users.`, } - userCmd.AddCommand(subcommands.CreateCmd) + userCmd.AddCommand(create.CreateCmd) + userCmd.AddCommand(verify.VerifyCmd) return userCmd } \ No newline at end of file diff --git a/cmd/user/verify/verify.go b/cmd/user/verify/verify.go new file mode 100644 index 0000000..233a1d9 --- /dev/null +++ b/cmd/user/verify/verify.go @@ -0,0 +1,96 @@ +package verify + +import ( + "errors" + "os" + "strings" + + "github.com/charmbracelet/huh" + "github.com/rs/zerolog/log" + "github.com/spf13/cobra" + "golang.org/x/crypto/bcrypt" +) + +var interactive bool +var username string +var password string +var docker bool +var user string + +var VerifyCmd = &cobra.Command{ + Use: "verify", + Short: "Verify a user is set up correctly", + Long: `Verify a user is set up correctly meaning that it has a correct password.`, + Run: func(cmd *cobra.Command, args []string) { + if interactive { + form := huh.NewForm( + huh.NewGroup( + huh.NewInput().Title("User (user:hash)").Value(&user).Validate((func(s string) error { + if s == "" { + return errors.New("user cannot be empty") + } + return nil + })), + huh.NewInput().Title("Username").Value(&username).Validate((func(s string) error { + if s == "" { + return errors.New("username cannot be empty") + } + return nil + })), + huh.NewInput().Title("Password").Value(&password).Validate((func(s string) error { + if s == "" { + return errors.New("password cannot be empty") + } + return nil + })), + huh.NewSelect[bool]().Title("Is the user formatted for docker?").Options(huh.NewOption("Yes", true), huh.NewOption("No", false)).Value(&docker), + ), + ) + + var baseTheme *huh.Theme = huh.ThemeBase() + + formErr := form.WithTheme(baseTheme).Run() + + if formErr != nil { + log.Fatal().Err(formErr).Msg("Form failed") + os.Exit(1) + } + } + + if username == "" || password == "" || user == "" { + log.Error().Msg("Username, password and user cannot be empty") + os.Exit(1) + } + + + log.Info().Str("user", user).Str("username", username).Str("password", password).Bool("docker", docker).Msg("Verifying user") + + userSplit := strings.Split(user, ":") + + if userSplit[1] == "" { + log.Error().Msg("User is not formatted correctly") + os.Exit(1) + } + + if docker { + userSplit[1] = strings.ReplaceAll(password, "$$", "$") + } + + verifyErr := bcrypt.CompareHashAndPassword([]byte(userSplit[1]), []byte(password)) + + if verifyErr != nil || username != userSplit[0] { + log.Error().Msg("Username or password incorrect") + os.Exit(1) + } else { + log.Info().Msg("Verification successful") + } + }, +} + +func init() { + VerifyCmd.Flags().BoolVarP(&interactive, "interactive", "i", false, "Create a user interactively") + VerifyCmd.Flags().BoolVar(&docker, "docker", false, "Is the user formatted for docker?") + VerifyCmd.Flags().StringVar(&username, "username", "", "Username") + VerifyCmd.Flags().StringVar(&password, "password", "", "Password") + VerifyCmd.Flags().StringVar(&user, "user", "", "Hash (user:hash combination)") +} \ No newline at end of file