github.com/iotexproject/iotex-core@v1.14.1-rc1/ioctl/newcmd/account/accountupdate.go (about)

     1  // Copyright (c) 2019 IoTeX Foundation
     2  // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
     3  // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
     4  // This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
     5  
     6  package account
     7  
     8  import (
     9  	"bytes"
    10  	"fmt"
    11  
    12  	"github.com/iotexproject/go-pkgs/crypto"
    13  	"github.com/iotexproject/go-pkgs/hash"
    14  	"github.com/iotexproject/iotex-address/address"
    15  	"github.com/pkg/errors"
    16  	"github.com/spf13/cobra"
    17  
    18  	"github.com/iotexproject/iotex-core/ioctl"
    19  	"github.com/iotexproject/iotex-core/ioctl/config"
    20  )
    21  
    22  // Multi-language support
    23  var (
    24  	_updateCmdShorts = map[config.Language]string{
    25  		config.English: "Update password for IoTeX account",
    26  		config.Chinese: "为IoTeX账户更新密码",
    27  	}
    28  	_updateCmdUses = map[config.Language]string{
    29  		config.English: "update [ALIAS|ADDRESS]",
    30  		config.Chinese: "update [别名|地址]",
    31  	}
    32  )
    33  
    34  // NewAccountUpdate represents the account update command
    35  func NewAccountUpdate(client ioctl.Client) *cobra.Command {
    36  	use, _ := client.SelectTranslation(_updateCmdUses)
    37  	short, _ := client.SelectTranslation(_updateCmdShorts)
    38  
    39  	return &cobra.Command{
    40  		Use:   use,
    41  		Short: short,
    42  		Args:  cobra.RangeArgs(0, 1),
    43  		RunE: func(cmd *cobra.Command, args []string) error {
    44  			cmd.SilenceUsage = true
    45  			arg := ""
    46  			if len(args) == 1 {
    47  				arg = args[0]
    48  			}
    49  
    50  			acc, err := client.AddressWithDefaultIfNotExist(arg)
    51  			if err != nil {
    52  				return err
    53  			}
    54  			addr, err := address.FromString(acc)
    55  			if err != nil {
    56  				return errors.Wrap(err, "failed to convert string into addr")
    57  			}
    58  
    59  			if client.IsCryptoSm2() {
    60  				// find the pem file and update
    61  				filePath, err := findSm2PemFile(client, addr)
    62  				if err != nil {
    63  					return errors.Wrapf(err, "crypto file of account #%s not found", addr)
    64  				}
    65  				if err = readSecretAndUpdate(client, cmd, acc,
    66  					func(currentPassword string) error {
    67  						_, err = crypto.ReadPrivateKeyFromPem(filePath, currentPassword)
    68  						if err != nil {
    69  							return errors.Wrap(err, "error occurs when checking current password")
    70  						}
    71  						return nil
    72  					},
    73  					func(currentPassword, newPassword string) error {
    74  						if err := crypto.UpdatePrivateKeyPasswordToPem(filePath, currentPassword, newPassword); err != nil {
    75  							return errors.Wrap(err, "failed to update pem file")
    76  						}
    77  						return nil
    78  					},
    79  				); err != nil {
    80  					return err
    81  				}
    82  			} else {
    83  				// find the keystore and update
    84  				ks := client.NewKeyStore()
    85  				for _, v := range ks.Accounts() {
    86  					if bytes.Equal(addr.Bytes(), v.Address.Bytes()) {
    87  						if err = readSecretAndUpdate(client, cmd, acc,
    88  							func(currentPassword string) error {
    89  								_, err = ks.SignHashWithPassphrase(v, currentPassword, hash.ZeroHash256[:])
    90  								if err != nil {
    91  									return errors.Wrap(err, "error occurs when checking current password")
    92  								}
    93  								return nil
    94  							},
    95  							func(currentPassword, newPassword string) error {
    96  								if err := ks.Update(v, currentPassword, newPassword); err != nil {
    97  									return errors.Wrap(err, "failed to update keystore")
    98  								}
    99  								return nil
   100  							},
   101  						); err != nil {
   102  							return err
   103  						}
   104  					}
   105  				}
   106  			}
   107  			cmd.Println(fmt.Sprintf("Account #%s has been updated.", acc))
   108  			return nil
   109  		},
   110  	}
   111  }
   112  
   113  func readSecretAndUpdate(client ioctl.Client, cmd *cobra.Command, acc string,
   114  	checkPwdFunc func(currentPassword string) error,
   115  	updatePwdFunc func(currentPassword, newPassword string) error) error {
   116  	cmd.Println(fmt.Sprintf("#%s: Enter current password\n", acc))
   117  	currentPassword, err := client.ReadSecret()
   118  	if err != nil {
   119  		return errors.Wrap(err, "failed to get current password")
   120  	}
   121  	if err = checkPwdFunc(currentPassword); err != nil {
   122  		return err
   123  	}
   124  	cmd.Println(fmt.Sprintf("#%s: Enter new password\n", acc))
   125  	newPassword, err := client.ReadSecret()
   126  	if err != nil {
   127  		return errors.Wrap(err, "failed to get new password")
   128  	}
   129  	cmd.Println(fmt.Sprintf("#%s: Enter new password again\n", acc))
   130  	newPasswordAgain, err := client.ReadSecret()
   131  	if err != nil {
   132  		return errors.Wrap(err, "failed to get new password")
   133  	}
   134  	if newPassword != newPasswordAgain {
   135  		return ErrPasswdNotMatch
   136  	}
   137  	return updatePwdFunc(currentPassword, newPassword)
   138  }