github.com/iotexproject/iotex-core@v1.14.1-rc1/ioctl/cmd/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/ethereum/go-ethereum/accounts/keystore"
    13  	"github.com/spf13/cobra"
    14  
    15  	"github.com/iotexproject/go-pkgs/crypto"
    16  	"github.com/iotexproject/go-pkgs/hash"
    17  	"github.com/iotexproject/iotex-address/address"
    18  
    19  	"github.com/iotexproject/iotex-core/ioctl/config"
    20  	"github.com/iotexproject/iotex-core/ioctl/output"
    21  	"github.com/iotexproject/iotex-core/ioctl/util"
    22  )
    23  
    24  // Multi-language support
    25  var (
    26  	_updateCmdShorts = map[config.Language]string{
    27  		config.English: "Update password for IoTeX account",
    28  		config.Chinese: "为IoTeX账户更新密码",
    29  	}
    30  	_updateCmdUses = map[config.Language]string{
    31  		config.English: "update [ALIAS|ADDRESS]",
    32  		config.Chinese: "update [别名|地址]",
    33  	}
    34  )
    35  
    36  // _accountUpdateCmd represents the account update command
    37  var _accountUpdateCmd = &cobra.Command{
    38  	Use:   config.TranslateInLang(_updateCmdUses, config.UILanguage),
    39  	Short: config.TranslateInLang(_updateCmdShorts, config.UILanguage),
    40  	Args:  cobra.RangeArgs(0, 1),
    41  	RunE: func(cmd *cobra.Command, args []string) error {
    42  		cmd.SilenceUsage = true
    43  		arg := ""
    44  		if len(args) == 1 {
    45  			arg = args[0]
    46  		}
    47  		err := accountUpdate(arg)
    48  		return output.PrintError(err)
    49  	},
    50  }
    51  
    52  func accountUpdate(arg string) error {
    53  	account, err := util.GetAddress(arg)
    54  	if err != nil {
    55  		return output.NewError(output.AddressError, "", err)
    56  	}
    57  	addr, err := address.FromString(account)
    58  	if err != nil {
    59  		return output.NewError(output.ConvertError, "failed to convert string into addr", err)
    60  	}
    61  
    62  	if CryptoSm2 {
    63  		// find the pem file and update
    64  		filePath, err := findSm2PemFile(addr)
    65  		if err != nil {
    66  			return output.NewError(output.ReadFileError, fmt.Sprintf("crypto file of account #%s not found", addr), err)
    67  		}
    68  
    69  		output.PrintQuery(fmt.Sprintf("#%s: Enter current password\n", account))
    70  		currentPassword, err := util.ReadSecretFromStdin()
    71  		if err != nil {
    72  			return output.NewError(output.InputError, "failed to get current password", err)
    73  		}
    74  		_, err = crypto.ReadPrivateKeyFromPem(filePath, currentPassword)
    75  		if err != nil {
    76  			return output.NewError(output.CryptoError, "error occurs when checking current password", err)
    77  		}
    78  		output.PrintQuery(fmt.Sprintf("#%s: Enter new password\n", account))
    79  		password, err := util.ReadSecretFromStdin()
    80  		if err != nil {
    81  			return output.NewError(output.InputError, "failed to get new password", err)
    82  		}
    83  		output.PrintQuery(fmt.Sprintf("#%s: Enter new password again\n", account))
    84  		passwordAgain, err := util.ReadSecretFromStdin()
    85  		if err != nil {
    86  			return output.NewError(output.InputError, "failed to get new password", err)
    87  		}
    88  		if password != passwordAgain {
    89  			return output.NewError(output.ValidationError, ErrPasswdNotMatch.Error(), nil)
    90  		}
    91  
    92  		if err := crypto.UpdatePrivateKeyPasswordToPem(filePath, currentPassword, password); err != nil {
    93  			return output.NewError(output.KeystoreError, "failed to update pem file", err)
    94  		}
    95  	} else {
    96  		// find the keystore and update
    97  		ks := keystore.NewKeyStore(config.ReadConfig.Wallet,
    98  			keystore.StandardScryptN, keystore.StandardScryptP)
    99  		for _, v := range ks.Accounts() {
   100  			if bytes.Equal(addr.Bytes(), v.Address.Bytes()) {
   101  				output.PrintQuery(fmt.Sprintf("#%s: Enter current password\n", account))
   102  				currentPassword, err := util.ReadSecretFromStdin()
   103  				if err != nil {
   104  					return output.NewError(output.InputError, "failed to get current password", err)
   105  				}
   106  				_, err = ks.SignHashWithPassphrase(v, currentPassword, hash.ZeroHash256[:])
   107  				if err != nil {
   108  					return output.NewError(output.KeystoreError, "error occurs when checking current password", err)
   109  				}
   110  				output.PrintQuery(fmt.Sprintf("#%s: Enter new password\n", account))
   111  				password, err := util.ReadSecretFromStdin()
   112  				if err != nil {
   113  					return output.NewError(output.InputError, "failed to get new password", err)
   114  				}
   115  				output.PrintQuery(fmt.Sprintf("#%s: Enter new password again\n", account))
   116  				passwordAgain, err := util.ReadSecretFromStdin()
   117  				if err != nil {
   118  					return output.NewError(output.InputError, "failed to get new password", err)
   119  				}
   120  				if password != passwordAgain {
   121  					return output.NewError(output.ValidationError, ErrPasswdNotMatch.Error(), nil)
   122  				}
   123  
   124  				if err := ks.Update(v, currentPassword, password); err != nil {
   125  					return output.NewError(output.KeystoreError, "failed to update keystore", err)
   126  				}
   127  
   128  				output.PrintResult(fmt.Sprintf("Account #%s has been updated.", account))
   129  				return nil
   130  			}
   131  		}
   132  	}
   133  
   134  	output.PrintResult(fmt.Sprintf("Account #%s has been updated.", account))
   135  	return nil
   136  }