func getPassPhrase(prompt string, confirmation bool, i int, passwords []string) string {
	if len(passwords) > 0 {
		if i < len(passwords) {
			return passwords[i]
		}
		return passwords[len(passwords)-1]
	}
	if prompt != "" {
		fmt.Println(prompt)
	}
	var password string
	fmt.Println("Passphrase: ")
	_, err := fmt.Scanln(&password)
	if err != nil {
		utils.Fatalf("Failed to read passphrase: %v", err)
	}
	if confirmation {
		fmt.Println("Repeat passphrase: ")
		var confirm string
		_, err := fmt.Scanln(&confirm)
		if err != nil {
			utils.Fatalf("Failed to read passphrase confirmation: %v", err)
		}
		if password != confirm {
			utils.Fatalf("Passphrases do not match")
		}
	}
	return password
}
getPassPhrase retrieves the password associated with an account, either fetched
from a list of preloaded passphrases, or requested interactively from the user.
package cmd
import (
	"fmt"
	"github.com/DSiSc/crypto-suite/crypto"
	"github.com/DSiSc/wallet/accounts"
	"github.com/DSiSc/wallet/accounts/keystore"
	"github.com/DSiSc/wallet/utils"
	"github.com/urfave/cli"
	"path/filepath"
)
var (
	AccountCommand = cli.Command{
		Name:     "account",
		Usage:    "Manage accounts",
		Category: "ACCOUNT COMMANDS",
		Description: `Manage accounts, list all existing accounts, import a private key into a new
account, create a new account or update an existing account.`,
		Subcommands: []cli.Command{
			{
				Name:   "list",
				Usage:  "Print summary of existing accounts",
				Action: utils.MigrateFlags(AccountList),
				Flags: []cli.Flag{
					utils.DataDirFlag,
					utils.KeyStoreDirFlag,
				},
				Description: `Print a short summary of all accounts`,
			},
			{
				Name:   "new",
				Usage:  "Create a new account",
				Action: utils.MigrateFlags(accountCreate),
				Flags: []cli.Flag{
					utils.DataDirFlag,
					utils.KeyStoreDirFlag,
					utils.PasswordFileFlag,
					utils.LightKDFFlag,
				},
				Description: `geth account new`,
			},
			{
				Name:   "update",
				Usage:  "Update an existing account",
				Action: utils.MigrateFlags(accountUpdate),
				Flags: []cli.Flag{
					utils.DataDirFlag,
					utils.KeyStoreDirFlag,
					utils.LightKDFFlag,
				},
				Description: `Update an existing account`,
			},
			{
				Name:   "import",
				Usage:  "Import a private key into a new account",
				Action: utils.MigrateFlags(accountImport),
				Flags: []cli.Flag{
					utils.DataDirFlag,
					utils.KeyStoreDirFlag,
					utils.PasswordFileFlag,
					utils.LightKDFFlag,
				},
				ArgsUsage:   "<keyFile>",
				Description: `Imports an unencrypted private key from <keyfile> and creates a new account`,
			},
		},
	}
)
func AccountList(ctx *cli.Context) error {
	var index int
	dataDir := ctx.GlobalString(utils.DataDirFlag.Name)
	keyStoreDir := ctx.GlobalString(utils.KeyStoreDirFlag.Name)
	if keyStoreDir == "" {
		keyStoreDir = keystore.KeyStoreScheme
	}
	keyStoreDir = filepath.Join(dataDir, keyStoreDir)
	manager, _, err := utils.MakeAccountManager(keyStoreDir)
	if err != nil {
		utils.Fatalf("Could not make account manager: %v", err)
	}
	for _, wallet := range manager.Wallets() {
		for _, account := range wallet.Accounts() {
			fmt.Printf("Account #%d: {%x} %s\n", index, account.Address, &account.URL)
			index++
		}
	}
	return nil
}
func unlockAccount(ctx *cli.Context, ks *keystore.KeyStore, address string, i int, passwords []string) (accounts.Account, string) {
	account, err := utils.MakeAddress(ks, address)
	if err != nil {
		utils.Fatalf("Could not list accounts: %v", err)
	}
	for trials := 0; trials < 3; trials++ {
		prompt := fmt.Sprintf("Unlocking account %s | Attempt %d/%d", address, trials+1, 3)
		password := getPassPhrase(prompt, false, i, passwords)
		err = ks.Unlock(account, password)
		if err == nil {
			return account, password
		}
		if err, ok := err.(*keystore.AmbiguousAddrError); ok {
			return ambiguousAddrRecovery(ks, err, password), password
		}
		if err != keystore.ErrDecrypt {
			break
		}
	}
	utils.Fatalf("Failed to unlock account %s (%v)", address, err)
	return accounts.Account{}, ""
}
func ambiguousAddrRecovery(ks *keystore.KeyStore, err *keystore.AmbiguousAddrError, auth string) accounts.Account {
	fmt.Printf("Multiple key files exist for address %x:\n", err.Addr)
	for _, a := range err.Matches {
		fmt.Println("  ", a.URL)
	}
	fmt.Println("Testing your passphrase against all of them...")
	var match *accounts.Account
	for _, a := range err.Matches {
		if err := ks.Unlock(a, auth); err == nil {
			match = &a
			break
		}
	}
	if match == nil {
		utils.Fatalf("None of the listed files could be unlocked.")
	}
	fmt.Printf("Your passphrase unlocked %s\n", match.URL)
	fmt.Println("In order to avoid this warning, you need to remove the following duplicate key files:")
	for _, a := range err.Matches {
		if a != *match {
			fmt.Println("  ", a.URL)
		}
	}
	return *match
}
func accountCreate(ctx *cli.Context) error {
	dataDir := ctx.GlobalString(utils.DataDirFlag.Name)
	keyStoreDir := ctx.GlobalString(utils.KeyStoreDirFlag.Name)
	if keyStoreDir == "" {
		keyStoreDir = keystore.KeyStoreScheme
	}
	keyStoreDir = filepath.Join(dataDir, keyStoreDir)
	password := getPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx))
	_, err := utils.NewAccount(keyStoreDir, password)
	return err
}
func accountUpdate(ctx *cli.Context) error {
	if len(ctx.Args()) == 0 {
		utils.Fatalf("No accounts specified to update")
	}
	dataDir := ctx.GlobalString(utils.DataDirFlag.Name)
	keyStoreDir := ctx.GlobalString(utils.KeyStoreDirFlag.Name)
	if keyStoreDir == "" {
		keyStoreDir = keystore.KeyStoreScheme
	}
	keyStoreDir = filepath.Join(dataDir, keyStoreDir)
	manager, _, _ := utils.MakeAccountManager(keyStoreDir)
	ks := manager.Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
	for _, addr := range ctx.Args() {
		account, oldPassword := unlockAccount(ctx, ks, addr, 0, nil)
		newPassword := getPassPhrase("Please give a new password. Do not forget this password.", true, 0, nil)
		if err := ks.Update(account, oldPassword, newPassword); err != nil {
			utils.Fatalf("Could not update the account: %v", err)
		}
	}
	return nil
}