Merge pull request #14388 from bas-vk/cli-account-mngt

cmd/geth: reorganise account/wallet command/flags
This commit is contained in:
Péter Szilágyi 2017-05-02 10:05:20 +03:00 committed by GitHub
commit 5884606ec3
3 changed files with 97 additions and 72 deletions

View File

@ -31,41 +31,33 @@ import (
var ( var (
walletCommand = cli.Command{ walletCommand = cli.Command{
Name: "wallet", Name: "wallet",
Usage: "Manage Ethereum presale wallets", Usage: "Import Ethereum presale wallets",
ArgsUsage: "", Action: utils.MigrateFlags(importWallet),
Category: "ACCOUNT COMMANDS", Category: "ACCOUNT COMMANDS",
Description: ` Flags: []cli.Flag{
geth wallet import /path/to/my/presale.wallet utils.DataDirFlag,
utils.KeyStoreDirFlag,
will prompt for your password and imports your ether presale account. utils.PasswordFileFlag,
It can be used non-interactively with the --password option taking a utils.LightKDFFlag,
passwordfile as argument containing the wallet password in plaintext.
`,
Subcommands: []cli.Command{
{
Action: importWallet,
Name: "import",
Usage: "Import Ethereum presale wallet",
ArgsUsage: "<keyFile>",
Description: `
TODO: Please write this
`,
},
}, },
Description: `
geth wallet [options] /path/to/my/presale.wallet
will prompt for your password and imports your ether presale account.
It can be used non-interactively with the --password option taking a
passwordfile as argument containing the wallet password in plaintext.
`,
} }
accountCommand = cli.Command{ accountCommand = cli.Command{
Action: accountList, Name: "account",
Name: "account", Usage: "Manage accounts",
Usage: "Manage accounts", Category: "ACCOUNT COMMANDS",
ArgsUsage: "",
Category: "ACCOUNT COMMANDS",
Description: ` Description: `
Manage accounts lets you create new accounts, list all existing accounts,
import a private key into a new account.
' help' shows a list of subcommands or help for one subcommand. Manage accounts, list all existing accounts, import a private key into a new
account, create a new account or update an existing account.
It supports interactive mode, when you are prompted for password as well as It supports interactive mode, when you are prompted for password as well as
non-interactive mode where passwords are supplied via a given password file. non-interactive mode where passwords are supplied via a given password file.
@ -80,36 +72,34 @@ Note that exporting your key in unencrypted format is NOT supported.
Keys are stored under <DATADIR>/keystore. Keys are stored under <DATADIR>/keystore.
It is safe to transfer the entire directory or the individual keys therein It is safe to transfer the entire directory or the individual keys therein
between ethereum nodes by simply copying. between ethereum nodes by simply copying.
Make sure you backup your keys regularly.
In order to use your account to send transactions, you need to unlock them using Make sure you backup your keys regularly.`,
the '--unlock' option. The argument is a space separated list of addresses or
indexes. If used non-interactively with a passwordfile, the file should contain
the respective passwords one per line. If you unlock n accounts and the password
file contains less than n entries, then the last password is meant to apply to
all remaining accounts.
And finally. DO NOT FORGET YOUR PASSWORD.
`,
Subcommands: []cli.Command{ Subcommands: []cli.Command{
{ {
Action: accountList, Name: "list",
Name: "list", Usage: "Print summary of existing accounts",
Usage: "Print account addresses", Action: utils.MigrateFlags(accountList),
ArgsUsage: " ", Flags: []cli.Flag{
utils.DataDirFlag,
utils.KeyStoreDirFlag,
},
Description: ` Description: `
TODO: Please write this Print a short summary of all accounts`,
`,
}, },
{ {
Action: accountCreate, Name: "new",
Name: "new", Usage: "Create a new account",
Usage: "Create a new account", Action: utils.MigrateFlags(accountCreate),
ArgsUsage: " ", Flags: []cli.Flag{
utils.DataDirFlag,
utils.KeyStoreDirFlag,
utils.PasswordFileFlag,
utils.LightKDFFlag,
},
Description: ` Description: `
geth account new geth account new
Creates a new account. Prints the address. Creates a new account and prints the address.
The account is saved in encrypted format, you are prompted for a passphrase. The account is saved in encrypted format, you are prompted for a passphrase.
@ -117,17 +107,20 @@ You must remember this passphrase to unlock your account in the future.
For non-interactive use the passphrase can be specified with the --password flag: For non-interactive use the passphrase can be specified with the --password flag:
geth --password <passwordfile> account new
Note, this is meant to be used for testing only, it is a bad idea to save your Note, this is meant to be used for testing only, it is a bad idea to save your
password to file or expose in any other way. password to file or expose in any other way.
`, `,
}, },
{ {
Action: accountUpdate,
Name: "update", Name: "update",
Usage: "Update an existing account", Usage: "Update an existing account",
Action: utils.MigrateFlags(accountUpdate),
ArgsUsage: "<address>", ArgsUsage: "<address>",
Flags: []cli.Flag{
utils.DataDirFlag,
utils.KeyStoreDirFlag,
utils.LightKDFFlag,
},
Description: ` Description: `
geth account update <address> geth account update <address>
@ -141,16 +134,22 @@ format to the newest format or change the password for an account.
For non-interactive use the passphrase can be specified with the --password flag: For non-interactive use the passphrase can be specified with the --password flag:
geth --password <passwordfile> account update <address> geth account update [options] <address>
Since only one password can be given, only format update can be performed, Since only one password can be given, only format update can be performed,
changing your password is only possible interactively. changing your password is only possible interactively.
`, `,
}, },
{ {
Action: accountImport, Name: "import",
Name: "import", Usage: "Import a private key into a new account",
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>", ArgsUsage: "<keyFile>",
Description: ` Description: `
geth account import <keyfile> geth account import <keyfile>
@ -166,7 +165,7 @@ You must remember this passphrase to unlock your account in the future.
For non-interactive use the passphrase can be specified with the -password flag: For non-interactive use the passphrase can be specified with the -password flag:
geth --password <passwordfile> account import <keyfile> geth account import [options] <keyfile>
Note: Note:
As you can directly copy your encrypted accounts to another ethereum instance, As you can directly copy your encrypted accounts to another ethereum instance,
@ -298,10 +297,12 @@ func accountUpdate(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx) stack, _ := makeConfigNode(ctx)
ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
account, oldPassword := unlockAccount(ctx, ks, ctx.Args().First(), 0, nil) for _, addr := range ctx.Args() {
newPassword := getPassPhrase("Please give a new password. Do not forget this password.", true, 0, nil) account, oldPassword := unlockAccount(ctx, ks, addr, 0, nil)
if err := ks.Update(account, oldPassword, newPassword); err != nil { newPassword := getPassPhrase("Please give a new password. Do not forget this password.", true, 0, nil)
utils.Fatalf("Could not update the account: %v", err) if err := ks.Update(account, oldPassword, newPassword); err != nil {
utils.Fatalf("Could not update the account: %v", err)
}
} }
return nil return nil
} }

View File

@ -43,13 +43,13 @@ func tmpDatadirWithKeystore(t *testing.T) string {
} }
func TestAccountListEmpty(t *testing.T) { func TestAccountListEmpty(t *testing.T) {
geth := runGeth(t, "account") geth := runGeth(t, "account", "list")
geth.expectExit() geth.expectExit()
} }
func TestAccountList(t *testing.T) { func TestAccountList(t *testing.T) {
datadir := tmpDatadirWithKeystore(t) datadir := tmpDatadirWithKeystore(t)
geth := runGeth(t, "--datadir", datadir, "account") geth := runGeth(t, "account", "list", "--datadir", datadir)
defer geth.expectExit() defer geth.expectExit()
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
geth.expect(` geth.expect(`
@ -67,7 +67,7 @@ Account #2: {289d485d9771714cce91d3393d764e1311907acc} keystore://{{.Datadir}}/k
} }
func TestAccountNew(t *testing.T) { func TestAccountNew(t *testing.T) {
geth := runGeth(t, "--lightkdf", "account", "new") geth := runGeth(t, "account", "new", "--lightkdf")
defer geth.expectExit() defer geth.expectExit()
geth.expect(` geth.expect(`
Your new account is locked with a password. Please give a password. Do not forget this password. Your new account is locked with a password. Please give a password. Do not forget this password.
@ -79,7 +79,7 @@ Repeat passphrase: {{.InputLine "foobar"}}
} }
func TestAccountNewBadRepeat(t *testing.T) { func TestAccountNewBadRepeat(t *testing.T) {
geth := runGeth(t, "--lightkdf", "account", "new") geth := runGeth(t, "account", "new", "--lightkdf")
defer geth.expectExit() defer geth.expectExit()
geth.expect(` geth.expect(`
Your new account is locked with a password. Please give a password. Do not forget this password. Your new account is locked with a password. Please give a password. Do not forget this password.
@ -92,9 +92,9 @@ Fatal: Passphrases do not match
func TestAccountUpdate(t *testing.T) { func TestAccountUpdate(t *testing.T) {
datadir := tmpDatadirWithKeystore(t) datadir := tmpDatadirWithKeystore(t)
geth := runGeth(t, geth := runGeth(t, "account", "update",
"--datadir", datadir, "--lightkdf", "--datadir", datadir, "--lightkdf",
"account", "update", "f466859ead1932d743d622cb74fc058882e8648a") "f466859ead1932d743d622cb74fc058882e8648a")
defer geth.expectExit() defer geth.expectExit()
geth.expect(` geth.expect(`
Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3 Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3
@ -107,7 +107,7 @@ Repeat passphrase: {{.InputLine "foobar2"}}
} }
func TestWalletImport(t *testing.T) { func TestWalletImport(t *testing.T) {
geth := runGeth(t, "--lightkdf", "wallet", "import", "testdata/guswallet.json") geth := runGeth(t, "wallet", "import", "--lightkdf", "testdata/guswallet.json")
defer geth.expectExit() defer geth.expectExit()
geth.expect(` geth.expect(`
!! Unsupported terminal, password will be echoed. !! Unsupported terminal, password will be echoed.
@ -122,7 +122,7 @@ Address: {d4584b5f6229b7be90727b0fc8c6b91bb427821f}
} }
func TestWalletImportBadPassword(t *testing.T) { func TestWalletImportBadPassword(t *testing.T) {
geth := runGeth(t, "--lightkdf", "wallet", "import", "testdata/guswallet.json") geth := runGeth(t, "wallet", "import", "--lightkdf", "testdata/guswallet.json")
defer geth.expectExit() defer geth.expectExit()
geth.expect(` geth.expect(`
!! Unsupported terminal, password will be echoed. !! Unsupported terminal, password will be echoed.

View File

@ -647,7 +647,7 @@ func setEtherbase(ctx *cli.Context, ks *keystore.KeyStore, cfg *eth.Config) {
} }
} }
// MakePasswordList reads password lines from the file specified by --password. // MakePasswordList reads password lines from the file specified by the global --password flag.
func MakePasswordList(ctx *cli.Context) []string { func MakePasswordList(ctx *cli.Context) []string {
path := ctx.GlobalString(PasswordFileFlag.Name) path := ctx.GlobalString(PasswordFileFlag.Name)
if path == "" { if path == "" {
@ -979,3 +979,27 @@ func MakeConsolePreloads(ctx *cli.Context) []string {
} }
return preloads return preloads
} }
// MigrateFlags sets the global flag from a local flag when it's set.
// This is a temporary function used for migrating old command/flags to the
// new format.
//
// e.g. geth account new --keystore /tmp/mykeystore --lightkdf
//
// is equivalent after calling this method with:
//
// geth --keystore /tmp/mykeystore --lightkdf account new
//
// This allows the use of the existing configuration functionality.
// When all flags are migrated this function can be removed and the existing
// configuration functionality must be changed that is uses local flags
func MigrateFlags(action func(ctx *cli.Context) error) func(*cli.Context) error {
return func(ctx *cli.Context) error {
for _, name := range ctx.FlagNames() {
if ctx.IsSet(name) {
ctx.GlobalSet(name, ctx.String(name))
}
}
return action(ctx)
}
}