From 86f2d9066886dfb78a3d4464be4cfe14fbe475cc Mon Sep 17 00:00:00 2001 From: IJustDev Date: Mon, 12 Oct 2020 00:15:48 +0200 Subject: [PATCH] feat(cli): Reset Password Command Introduce `reset-password` command. Refs #71 --- internal/commands/commands.go | 2 +- internal/commands/reset_password.go | 68 +++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 internal/commands/reset_password.go diff --git a/internal/commands/commands.go b/internal/commands/commands.go index 9c45896..aa4f0cd 100644 --- a/internal/commands/commands.go +++ b/internal/commands/commands.go @@ -67,6 +67,6 @@ func initConfig() { // Execute the root cobra command func Execute() { rootCmd.SetVersionTemplate(versionTemplate) - rootCmd.AddCommand(newWebCmd(), newMigrateCmd(), newTokenCmd(), newWorkerCmd()) + rootCmd.AddCommand(newWebCmd(), newMigrateCmd(), newTokenCmd(), newWorkerCmd(), newResetPasswordCmd()) rootCmd.Execute() } diff --git a/internal/commands/reset_password.go b/internal/commands/reset_password.go new file mode 100644 index 0000000..f009a36 --- /dev/null +++ b/internal/commands/reset_password.go @@ -0,0 +1,68 @@ +package commands + +import ( + "context" + "fmt" + "time" + + "github.com/jmoiron/sqlx" + "github.com/jordanknott/taskcafe/internal/db" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" + "golang.org/x/crypto/bcrypt" +) + +func newResetPasswordCmd() *cobra.Command { + return &cobra.Command{ + Use: "reset-password", + Short: "Resets password of the specified user", + Long: "If the user forgets its password you can reset it with this command.", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + connection := fmt.Sprintf("user=%s password=%s host=%s dbname=%s sslmode=disable", + viper.GetString("database.user"), + viper.GetString("database.password"), + viper.GetString("database.host"), + viper.GetString("database.name"), + ) + var database *sqlx.DB + var err error + var retryDuration time.Duration + maxRetryNumber := 4 + for i := 0; i < maxRetryNumber; i++ { + database, err = sqlx.Connect("postgres", connection) + if err == nil { + break + } + retryDuration = time.Duration(i*2) * time.Second + log.WithFields(log.Fields{"retryNumber": i, "retryDuration": retryDuration}).WithError(err).Error("issue connecting to database, retrying") + if i != maxRetryNumber-1 { + time.Sleep(retryDuration) + } + } + database.SetMaxOpenConns(25) + database.SetMaxIdleConns(25) + database.SetConnMaxLifetime(5 * time.Minute) + repo := *db.NewRepository(database) + + username := args[0] + password := args[1] + + user, err := repo.GetUserAccountByUsername(context.TODO(), username) + if err != nil { + fmt.Println("There is no user with that username. :/") + return nil + } + + hashedPwd, err := bcrypt.GenerateFromPassword([]byte(password), 14) + + if _, err := repo.SetUserPassword(context.TODO(), db.SetUserPasswordParams{UserID: user.UserID, PasswordHash: string(hashedPwd)}); err != nil { + return err + } + fmt.Println("Updated user \"" + username + "\" password.") + defer database.Close() + return nil + }, + } +}