forked from TrueCloudLab/neoneo-go
Merge pull request #2327 from nspcc-dev/change-wallet-acc-password
cli/wallet: add change-password command, fix #2233
This commit is contained in:
commit
a23943c161
2 changed files with 143 additions and 7 deletions
|
@ -105,6 +105,18 @@ func NewCommands() []cli.Command {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "change-password",
|
||||
Usage: "change password for accounts",
|
||||
Action: changePassword,
|
||||
Flags: []cli.Flag{
|
||||
walletPathFlag,
|
||||
flags.AddressFlag{
|
||||
Name: "address, a",
|
||||
Usage: "address to change password for",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "convert",
|
||||
Usage: "convert addresses from existing NEO2 NEP6-wallet to NEO3 format",
|
||||
|
@ -289,6 +301,55 @@ func claimGas(ctx *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func changePassword(ctx *cli.Context) error {
|
||||
wall, err := openWallet(ctx.String("wallet"))
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
addrFlag := ctx.Generic("address").(*flags.Address)
|
||||
if addrFlag.IsSet {
|
||||
// Check for account presence first before asking for password.
|
||||
acc := wall.GetAccount(addrFlag.Uint160())
|
||||
if acc == nil {
|
||||
return cli.NewExitError("account is missing", 1)
|
||||
}
|
||||
}
|
||||
|
||||
oldPass, err := input.ReadPassword("Enter password > ")
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("Error reading old password: %w", err), 1)
|
||||
}
|
||||
|
||||
for i := range wall.Accounts {
|
||||
if addrFlag.IsSet && wall.Accounts[i].Address != addrFlag.String() {
|
||||
continue
|
||||
}
|
||||
err := wall.Accounts[i].Decrypt(oldPass, wall.Scrypt)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("unable to decrypt account %s: %w", wall.Accounts[i].Address, err), 1)
|
||||
}
|
||||
}
|
||||
|
||||
pass, err := readNewPassword()
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("Error reading new password: %w", err), 1)
|
||||
}
|
||||
for i := range wall.Accounts {
|
||||
if addrFlag.IsSet && wall.Accounts[i].Address != addrFlag.String() {
|
||||
continue
|
||||
}
|
||||
err := wall.Accounts[i].Encrypt(pass, wall.Scrypt)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
}
|
||||
err = wall.Save()
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("Error saving the wallet: %w", err), 1)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func convertWallet(ctx *cli.Context) error {
|
||||
wall, err := newWalletV2FromFile(ctx.String("wallet"))
|
||||
if err != nil {
|
||||
|
@ -656,22 +717,31 @@ func createWallet(ctx *cli.Context) error {
|
|||
}
|
||||
|
||||
func readAccountInfo() (string, string, error) {
|
||||
rawName, _ := input.ReadLine("Enter the name of the account > ")
|
||||
name, err := input.ReadLine("Enter the name of the account > ")
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
phrase, err := readNewPassword()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
return name, phrase, nil
|
||||
}
|
||||
|
||||
func readNewPassword() (string, error) {
|
||||
phrase, err := input.ReadPassword("Enter passphrase > ")
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("Error reading password: %w", err)
|
||||
return "", fmt.Errorf("Error reading password: %w", err)
|
||||
}
|
||||
phraseCheck, err := input.ReadPassword("Confirm passphrase > ")
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("Error reading password: %w", err)
|
||||
return "", fmt.Errorf("Error reading password: %w", err)
|
||||
}
|
||||
|
||||
if phrase != phraseCheck {
|
||||
return "", "", errPhraseMismatch
|
||||
return "", errPhraseMismatch
|
||||
}
|
||||
|
||||
name := strings.TrimRight(rawName, "\n")
|
||||
return name, phrase, nil
|
||||
return phrase, nil
|
||||
}
|
||||
|
||||
func createAccount(wall *wallet.Wallet) error {
|
||||
|
|
|
@ -45,6 +45,72 @@ func TestWalletAccountRemove(t *testing.T) {
|
|||
require.NoError(t, json.Unmarshal(rawWallet, new(wallet.Wallet)))
|
||||
}
|
||||
|
||||
func TestWalletChangePassword(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
e := newExecutor(t, false)
|
||||
|
||||
walletPath := filepath.Join(tmpDir, "wallet.json")
|
||||
e.In.WriteString("acc1\r")
|
||||
e.In.WriteString("pass\r")
|
||||
e.In.WriteString("pass\r")
|
||||
e.Run(t, "neo-go", "wallet", "init", "--wallet", walletPath, "--account")
|
||||
|
||||
e.In.WriteString("acc2\r")
|
||||
e.In.WriteString("pass\r")
|
||||
e.In.WriteString("pass\r")
|
||||
e.Run(t, "neo-go", "wallet", "create", "--wallet", walletPath)
|
||||
|
||||
w, err := wallet.NewWalletFromFile(walletPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
addr1 := w.Accounts[0].Address
|
||||
addr2 := w.Accounts[1].Address
|
||||
t.Run("bad old password", func(t *testing.T) {
|
||||
e.In.WriteString("ssap\r")
|
||||
e.In.WriteString("aaa\r") // Pretend for the password to be fine.
|
||||
e.In.WriteString("aaa\r")
|
||||
|
||||
e.RunWithError(t, "neo-go", "wallet", "change-password", "--wallet", walletPath)
|
||||
})
|
||||
t.Run("no account", func(t *testing.T) {
|
||||
e.RunWithError(t, "neo-go", "wallet", "change-password", "--wallet", walletPath, "--address", "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq")
|
||||
})
|
||||
t.Run("bad new password, multiaccount", func(t *testing.T) {
|
||||
e.In.WriteString("pass\r")
|
||||
e.In.WriteString("pass1\r")
|
||||
e.In.WriteString("pass2\r")
|
||||
e.RunWithError(t, "neo-go", "wallet", "change-password", "--wallet", walletPath)
|
||||
})
|
||||
t.Run("good, multiaccount", func(t *testing.T) {
|
||||
e.In.WriteString("pass\r")
|
||||
e.In.WriteString("asdf\r")
|
||||
e.In.WriteString("asdf\r")
|
||||
e.Run(t, "neo-go", "wallet", "change-password", "--wallet", walletPath)
|
||||
})
|
||||
t.Run("good, single account", func(t *testing.T) {
|
||||
e.In.WriteString("asdf\r")
|
||||
e.In.WriteString("jkl\r")
|
||||
e.In.WriteString("jkl\r")
|
||||
e.Run(t, "neo-go", "wallet", "change-password", "--wallet", walletPath, "--address", addr1)
|
||||
})
|
||||
t.Run("bad, different passwords", func(t *testing.T) {
|
||||
e.In.WriteString("jkl\r")
|
||||
e.RunWithError(t, "neo-go", "wallet", "change-password", "--wallet", walletPath)
|
||||
})
|
||||
t.Run("good, second account", func(t *testing.T) {
|
||||
e.In.WriteString("asdf\r")
|
||||
e.In.WriteString("jkl\r")
|
||||
e.In.WriteString("jkl\r")
|
||||
e.Run(t, "neo-go", "wallet", "change-password", "--wallet", walletPath, "--address", addr2)
|
||||
})
|
||||
t.Run("good, second multiaccount", func(t *testing.T) {
|
||||
e.In.WriteString("jkl\r")
|
||||
e.In.WriteString("pass\r")
|
||||
e.In.WriteString("pass\r")
|
||||
e.Run(t, "neo-go", "wallet", "change-password", "--wallet", walletPath)
|
||||
})
|
||||
}
|
||||
|
||||
func TestWalletInit(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
e := newExecutor(t, false)
|
||||
|
|
Loading…
Reference in a new issue