diff --git a/client/keys/add.go b/client/keys/add.go index c4987feef0..d7f3dded67 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -5,10 +5,12 @@ import ( "bytes" "errors" "fmt" - "io" "sort" bip39 "github.com/cosmos/go-bip39" + "github.com/spf13/cobra" + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/libs/cli" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/input" @@ -16,12 +18,6 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/crypto/types/multisig" sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "github.com/tendermint/tendermint/crypto" - "github.com/tendermint/tendermint/libs/cli" ) const ( @@ -65,8 +61,9 @@ the flag --nosort is set. Args: cobra.ExactArgs(1), RunE: runAddCmd, } + cmd.Flags().StringSlice(flagMultisig, nil, "Construct and store a multisig public key (implies --pubkey)") - cmd.Flags().Uint(flagMultiSigThreshold, 1, "K out of N required signatures. For use in conjunction with --multisig") + cmd.Flags().Int(flagMultiSigThreshold, 1, "K out of N required signatures. For use in conjunction with --multisig") cmd.Flags().Bool(flagNoSort, false, "Keys passed to --multisig are taken in the order they're supplied") cmd.Flags().String(FlagPublicKey, "", "Parse a public key in bech32 format and save it to disk") cmd.Flags().BoolP(flagInteractive, "i", false, "Interactively prompt user for BIP39 passphrase and mnemonic") @@ -86,23 +83,29 @@ the flag --nosort is set. return cmd } -func getKeybase(transient bool, buf io.Reader) (keyring.Keyring, error) { - if transient { - return keyring.New(sdk.KeyringServiceName(), keyring.BackendMemory, viper.GetString(flags.FlagHome), buf) - } - - return keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) -} - func runAddCmd(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - kb, err := getKeybase(viper.GetBool(flags.FlagDryRun), inBuf) + buf := bufio.NewReader(cmd.InOrStdin()) + + homeDir, _ := cmd.Flags().GetString(flags.FlagHome) + dryRun, _ := cmd.Flags().GetBool(flags.FlagHome) + + var ( + kr keyring.Keyring + err error + ) + + if dryRun { + kr, err = keyring.New(sdk.KeyringServiceName(), keyring.BackendMemory, homeDir, buf) + } else { + backend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend) + kr, err = keyring.New(sdk.KeyringServiceName(), backend, homeDir, buf) + } if err != nil { return err } - return RunAddCmd(cmd, args, kb, inBuf) + return RunAddCmd(cmd, args, kr, buf) } /* @@ -118,16 +121,18 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keyring.Keyring, inBuf *buf var err error name := args[0] - interactive := viper.GetBool(flagInteractive) - showMnemonic := !viper.GetBool(flagNoBackup) + interactive, _ := cmd.Flags().GetBool(flagInteractive) + noBackup, _ := cmd.Flags().GetBool(flagNoBackup) + showMnemonic := !noBackup keyringAlgos, _ := kb.SupportedAlgorithms() - algo, err := keyring.NewSigningAlgoFromString(viper.GetString(flagKeyAlgo), keyringAlgos) + algoStr, _ := cmd.Flags().GetString(flagKeyAlgo) + algo, err := keyring.NewSigningAlgoFromString(algoStr, keyringAlgos) if err != nil { return err } - if !viper.GetBool(flags.FlagDryRun) { + if dryRun, _ := cmd.Flags().GetBool(flags.FlagDryRun); !dryRun { _, err = kb.Key(name) if err == nil { // account exists, ask for user confirmation @@ -146,11 +151,11 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keyring.Keyring, inBuf *buf } } - multisigKeys := viper.GetStringSlice(flagMultisig) + multisigKeys, _ := cmd.Flags().GetStringSlice(flagMultisig) if len(multisigKeys) != 0 { var pks []crypto.PubKey - multisigThreshold := viper.GetInt(flagMultiSigThreshold) + multisigThreshold, _ := cmd.Flags().GetInt(flagMultiSigThreshold) if err := validateMultisigThreshold(multisigThreshold, len(multisigKeys)); err != nil { return err } @@ -164,8 +169,7 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keyring.Keyring, inBuf *buf pks = append(pks, k.GetPubKey()) } - // Handle --nosort - if !viper.GetBool(flagNoSort) { + if noSort, _ := cmd.Flags().GetBool(flagNoSort); !noSort { sort.Slice(pks, func(i, j int) bool { return bytes.Compare(pks[i].Address(), pks[j].Address()) < 0 }) @@ -177,13 +181,13 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keyring.Keyring, inBuf *buf } cmd.PrintErrf("Key %q saved to disk.\n", name) - return nil } } - if viper.GetString(FlagPublicKey) != "" { - pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, viper.GetString(FlagPublicKey)) + pubKey, _ := cmd.Flags().GetString(FlagPublicKey) + if pubKey != "" { + pk, err := sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeAccPub, pubKey) if err != nil { return err } @@ -195,19 +199,20 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keyring.Keyring, inBuf *buf return nil } - coinType := uint32(viper.GetInt(flagCoinType)) - account := uint32(viper.GetInt(flagAccount)) - index := uint32(viper.GetInt(flagIndex)) - hdPath := viper.GetString(flagHDPath) + coinType, _ := cmd.Flags().GetUint32(flagCoinType) + account, _ := cmd.Flags().GetUint32(flagAccount) + index, _ := cmd.Flags().GetUint32(flagIndex) + hdPath, _ := cmd.Flags().GetString(flagHDPath) + useLedger, _ := cmd.Flags().GetBool(flags.FlagUseLedger) if len(hdPath) == 0 { hdPath = hd.CreateHDPath(coinType, account, index).String() - } else if viper.GetBool(flags.FlagUseLedger) { + } else if useLedger { return errors.New("cannot set custom bip32 path with ledger") } // If we're using ledger, only thing we need is the path and the bech32 prefix. - if viper.GetBool(flags.FlagUseLedger) { + if useLedger { bech32PrefixAccAddr := sdk.GetConfig().GetBech32AccountAddrPrefix() info, err := kb.SaveLedgerKey(name, hd.Secp256k1, bech32PrefixAccAddr, coinType, account, index) @@ -221,9 +226,10 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keyring.Keyring, inBuf *buf // Get bip39 mnemonic var mnemonic, bip39Passphrase string - if interactive || viper.GetBool(flagRecover) { + recover, _ := cmd.Flags().GetBool(flagRecover) + if interactive || recover { bip39Message := "Enter your bip39 mnemonic" - if !viper.GetBool(flagRecover) { + if !recover { bip39Message = "Enter your bip39 mnemonic, or hit enter to generate one." } @@ -278,7 +284,7 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keyring.Keyring, inBuf *buf } // Recover key from seed passphrase - if viper.GetBool(flagRecover) { + if recover { // Hide mnemonic from output showMnemonic = false mnemonic = "" @@ -288,12 +294,12 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keyring.Keyring, inBuf *buf } func printCreate(cmd *cobra.Command, info keyring.Info, showMnemonic bool, mnemonic string) error { - output := viper.Get(cli.OutputFlag) + output, _ := cmd.Flags().GetString(cli.OutputFlag) switch output { case OutputFormatText: cmd.PrintErrln() - printKeyInfo(cmd.OutOrStdout(), info, keyring.Bech32KeyOutput) + printKeyInfo(cmd.OutOrStdout(), info, keyring.Bech32KeyOutput, output) // print mnemonic unless requested not to. if showMnemonic { diff --git a/client/keys/add_ledger_test.go b/client/keys/add_ledger_test.go index e19db3dd9a..3820e418d7 100644 --- a/client/keys/add_ledger_test.go +++ b/client/keys/add_ledger_test.go @@ -3,9 +3,9 @@ package keys import ( + "fmt" "testing" - "github.com/spf13/viper" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/libs/cli" @@ -34,29 +34,31 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) { config.SetBech32PrefixForConsensusNode(bech32PrefixConsAddr, bech32PrefixConsPub) cmd := AddKeyCommand() - require.NotNil(t, cmd) + cmd.Flags().AddFlagSet(Commands().PersistentFlags()) // Prepare a keybase kbHome, kbCleanUp := tests.NewTestCaseDir(t) require.NotNil(t, kbHome) t.Cleanup(kbCleanUp) - viper.Set(flags.FlagHome, kbHome) - viper.Set(flags.FlagUseLedger, true) - viper.Set(flagAccount, "0") - viper.Set(flagIndex, "0") - viper.Set(flagCoinType, "330") - // Test Text - viper.Set(cli.OutputFlag, OutputFormatText) - // set algo flag value to the default - viper.Set(flagKeyAlgo, string(hd.Secp256k1Type)) - // Now enter password + cmd.SetArgs([]string{ + "keyname1", + fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), + fmt.Sprintf("--%s=true", flags.FlagUseLedger), + fmt.Sprintf("--%s=0", flagAccount), + fmt.Sprintf("--%s=0", flagIndex), + fmt.Sprintf("--%s=330", flagCoinType), + fmt.Sprintf("--%s=%s", cli.OutputFlag, OutputFormatText), + fmt.Sprintf("--%s=%s", flagKeyAlgo, string(hd.Secp256k1Type)), + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + }) + mockIn, _, _ := tests.ApplyMockIO(cmd) mockIn.Reset("test1234\ntest1234\n") - require.NoError(t, runAddCmd(cmd, []string{"keyname1"})) + require.NoError(t, cmd.Execute()) // Now check that it has been stored properly - kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) + kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn) require.NoError(t, err) require.NotNil(t, kb) t.Cleanup(func() { @@ -82,32 +84,35 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) { func Test_runAddCmdLedger(t *testing.T) { cmd := AddKeyCommand() - require.NotNil(t, cmd) + cmd.Flags().AddFlagSet(Commands().PersistentFlags()) mockIn, _, _ := tests.ApplyMockIO(cmd) // Prepare a keybase kbHome, kbCleanUp := tests.NewTestCaseDir(t) require.NotNil(t, kbHome) t.Cleanup(kbCleanUp) - viper.Set(flags.FlagHome, kbHome) - viper.Set(flags.FlagUseLedger, true) - // Test Text - viper.Set(cli.OutputFlag, OutputFormatText) - // set algo flag value to the default - viper.Set(flagKeyAlgo, string(hd.Secp256k1Type)) - // Now enter password + cmd.SetArgs([]string{ + "keyname1", + fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), + fmt.Sprintf("--%s=true", flags.FlagUseLedger), + fmt.Sprintf("--%s=%s", cli.OutputFlag, OutputFormatText), + fmt.Sprintf("--%s=%s", flagKeyAlgo, string(hd.Secp256k1Type)), + fmt.Sprintf("--%s=%d", flagCoinType, sdk.CoinType), + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + }) mockIn.Reset("test1234\ntest1234\n") - viper.Set(flagCoinType, sdk.CoinType) - require.NoError(t, runAddCmd(cmd, []string{"keyname1"})) + + require.NoError(t, cmd.Execute()) // Now check that it has been stored properly - kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) + kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn) require.NoError(t, err) require.NotNil(t, kb) t.Cleanup(func() { _ = kb.Delete("keyname1") }) + mockIn.Reset("test1234\n") key1, err := kb.Key("keyname1") require.NoError(t, err) diff --git a/client/keys/add_test.go b/client/keys/add_test.go index d5532ef3db..0b6af85b1d 100644 --- a/client/keys/add_test.go +++ b/client/keys/add_test.go @@ -1,9 +1,9 @@ package keys import ( + "fmt" "testing" - "github.com/spf13/viper" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/libs/cli" @@ -17,41 +17,66 @@ import ( func Test_runAddCmdBasic(t *testing.T) { cmd := AddKeyCommand() - require.NotNil(t, cmd) + cmd.Flags().AddFlagSet(Commands().PersistentFlags()) mockIn, _, _ := tests.ApplyMockIO(cmd) kbHome, kbCleanUp := tests.NewTestCaseDir(t) require.NotNil(t, kbHome) t.Cleanup(kbCleanUp) - viper.Set(flags.FlagHome, kbHome) - viper.Set(cli.OutputFlag, OutputFormatText) - viper.Set(flags.FlagUseLedger, false) - mockIn.Reset("y\n") - // set algo flag value to the default - viper.Set(flagKeyAlgo, string(hd.Secp256k1Type)) - - kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) + kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn) require.NoError(t, err) t.Cleanup(func() { _ = kb.Delete("keyname1") _ = kb.Delete("keyname2") }) - require.NoError(t, runAddCmd(cmd, []string{"keyname1"})) + + cmd.SetArgs([]string{ + "keyname1", + fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), + fmt.Sprintf("--%s=%s", cli.OutputFlag, OutputFormatText), + fmt.Sprintf("--%s=%s", flagKeyAlgo, string(hd.Secp256k1Type)), + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + }) + mockIn.Reset("y\n") + require.NoError(t, cmd.Execute()) mockIn.Reset("N\n") - require.Error(t, runAddCmd(cmd, []string{"keyname1"})) + require.Error(t, cmd.Execute()) + + cmd.SetArgs([]string{ + "keyname2", + fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), + fmt.Sprintf("--%s=%s", cli.OutputFlag, OutputFormatText), + fmt.Sprintf("--%s=%s", flagKeyAlgo, string(hd.Secp256k1Type)), + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + }) + + require.NoError(t, cmd.Execute()) + require.Error(t, cmd.Execute()) - require.NoError(t, runAddCmd(cmd, []string{"keyname2"})) - require.Error(t, runAddCmd(cmd, []string{"keyname2"})) mockIn.Reset("y\n") - require.NoError(t, runAddCmd(cmd, []string{"keyname2"})) + require.NoError(t, cmd.Execute()) - // test --dry-run - require.NoError(t, runAddCmd(cmd, []string{"keyname4"})) - require.Error(t, runAddCmd(cmd, []string{"keyname4"})) + cmd.SetArgs([]string{ + "keyname4", + fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), + fmt.Sprintf("--%s=%s", cli.OutputFlag, OutputFormatText), + fmt.Sprintf("--%s=%s", flagKeyAlgo, string(hd.Secp256k1Type)), + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + }) - viper.Set(flags.FlagDryRun, true) - require.NoError(t, runAddCmd(cmd, []string{"keyname4"})) + require.NoError(t, cmd.Execute()) + require.Error(t, cmd.Execute()) + + cmd.SetArgs([]string{ + "keyname5", + fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), + fmt.Sprintf("--%s=true", flags.FlagDryRun), + fmt.Sprintf("--%s=%s", cli.OutputFlag, OutputFormatText), + fmt.Sprintf("--%s=%s", flagKeyAlgo, string(hd.Secp256k1Type)), + }) + + require.NoError(t, cmd.Execute()) } diff --git a/client/keys/delete.go b/client/keys/delete.go index e050196999..644598109b 100644 --- a/client/keys/delete.go +++ b/client/keys/delete.go @@ -9,7 +9,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/spf13/cobra" - "github.com/spf13/viper" ) const ( @@ -28,50 +27,49 @@ Note that removing offline or ledger keys will remove only the public key references stored locally, i.e. private keys stored in a ledger device cannot be deleted with the CLI. `, - RunE: runDeleteCmd, Args: cobra.MinimumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + buf := bufio.NewReader(cmd.InOrStdin()) + + backend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend) + homeDir, _ := cmd.Flags().GetString(flags.FlagHome) + kb, err := keyring.New(sdk.KeyringServiceName(), backend, homeDir, buf) + if err != nil { + return err + } + + for _, name := range args { + info, err := kb.Key(name) + if err != nil { + return err + } + + // confirm deletion, unless -y is passed + if skip, _ := cmd.Flags().GetBool(flagYes); !skip { + if yes, err := input.GetConfirmation("Key reference will be deleted. Continue?", buf, cmd.ErrOrStderr()); err != nil { + return err + } else if !yes { + continue + } + } + + if err := kb.Delete(name); err != nil { + return err + } + + if info.GetType() == keyring.TypeLedger || info.GetType() == keyring.TypeOffline { + cmd.PrintErrln("Public key reference deleted") + continue + } + cmd.PrintErrln("Key deleted forever (uh oh!)") + } + + return nil + }, } - cmd.Flags().BoolP(flagYes, "y", false, - "Skip confirmation prompt when deleting offline or ledger key references") - cmd.Flags().BoolP(flagForce, "f", false, - "Remove the key unconditionally without asking for the passphrase. Deprecated.") + cmd.Flags().BoolP(flagYes, "y", false, "Skip confirmation prompt when deleting offline or ledger key references") + cmd.Flags().BoolP(flagForce, "f", false, "Remove the key unconditionally without asking for the passphrase. Deprecated.") + return cmd } - -func runDeleteCmd(cmd *cobra.Command, args []string) error { - buf := bufio.NewReader(cmd.InOrStdin()) - - kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) - if err != nil { - return err - } - - for _, name := range args { - info, err := kb.Key(name) - if err != nil { - return err - } - - // confirm deletion, unless -y is passed - if !viper.GetBool(flagYes) { - if yes, err := input.GetConfirmation("Key reference will be deleted. Continue?", buf, cmd.ErrOrStderr()); err != nil { - return err - } else if !yes { - continue - } - } - - if err := kb.Delete(name); err != nil { - return err - } - - if info.GetType() == keyring.TypeLedger || info.GetType() == keyring.TypeOffline { - cmd.PrintErrln("Public key reference deleted") - continue - } - cmd.PrintErrln("Key deleted forever (uh oh!)") - } - - return nil -} diff --git a/client/keys/delete_test.go b/client/keys/delete_test.go index 3d2136a725..ede5e72db2 100644 --- a/client/keys/delete_test.go +++ b/client/keys/delete_test.go @@ -1,25 +1,25 @@ package keys import ( + "fmt" "testing" - "github.com/spf13/viper" "github.com/stretchr/testify/require" - "github.com/cosmos/cosmos-sdk/crypto/hd" - "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" ) func Test_runDeleteCmd(t *testing.T) { - deleteKeyCommand := DeleteKeyCommand() - mockIn, _, _ := tests.ApplyMockIO(deleteKeyCommand) + cmd := DeleteKeyCommand() + cmd.Flags().AddFlagSet(Commands().PersistentFlags()) + mockIn, _, _ := tests.ApplyMockIO(cmd) - yesF, _ := deleteKeyCommand.Flags().GetBool(flagYes) - forceF, _ := deleteKeyCommand.Flags().GetBool(flagForce) + yesF, _ := cmd.Flags().GetBool(flagYes) + forceF, _ := cmd.Flags().GetBool(flagForce) require.False(t, yesF) require.False(t, forceF) @@ -29,24 +29,30 @@ func Test_runDeleteCmd(t *testing.T) { // Now add a temporary keybase kbHome, cleanUp := tests.NewTestCaseDir(t) t.Cleanup(cleanUp) - viper.Set(flags.FlagHome, kbHome) - // Now path := sdk.GetConfig().GetFullFundraiserPath() - backend := viper.GetString(flags.FlagKeyringBackend) - kb, err := keyring.New(sdk.KeyringServiceName(), backend, kbHome, mockIn) + + kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn) require.NoError(t, err) + _, err = kb.NewAccount(fakeKeyName1, tests.TestMnemonic, "", path, hd.Secp256k1) require.NoError(t, err) + _, _, err = kb.NewMnemonic(fakeKeyName2, keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) require.NoError(t, err) - err = runDeleteCmd(deleteKeyCommand, []string{"blah"}) + cmd.SetArgs([]string{"blah", fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome)}) + err = cmd.Execute() require.Error(t, err) require.Equal(t, "The specified item could not be found in the keyring", err.Error()) // User confirmation missing - err = runDeleteCmd(deleteKeyCommand, []string{fakeKeyName1}) + cmd.SetArgs([]string{ + fakeKeyName1, + fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + }) + err = cmd.Execute() require.Error(t, err) require.Equal(t, "EOF", err.Error()) @@ -54,17 +60,28 @@ func Test_runDeleteCmd(t *testing.T) { require.NoError(t, err) // Now there is a confirmation - viper.Set(flagYes, true) - require.NoError(t, runDeleteCmd(deleteKeyCommand, []string{fakeKeyName1})) + cmd.SetArgs([]string{ + fakeKeyName1, + fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), + fmt.Sprintf("--%s=true", flagYes), + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + }) + require.NoError(t, cmd.Execute()) _, err = kb.Key(fakeKeyName1) require.Error(t, err) // Key1 is gone - viper.Set(flagYes, true) _, err = kb.Key(fakeKeyName2) require.NoError(t, err) - err = runDeleteCmd(deleteKeyCommand, []string{fakeKeyName2}) - require.NoError(t, err) + + cmd.SetArgs([]string{ + fakeKeyName2, + fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), + fmt.Sprintf("--%s=true", flagYes), + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + }) + require.NoError(t, cmd.Execute()) + _, err = kb.Key(fakeKeyName2) require.Error(t, err) // Key2 is gone } diff --git a/client/keys/export.go b/client/keys/export.go index 2c17bfe84f..e2248a2f18 100644 --- a/client/keys/export.go +++ b/client/keys/export.go @@ -4,7 +4,6 @@ import ( "bufio" "github.com/spf13/cobra" - "github.com/spf13/viper" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/input" @@ -19,27 +18,28 @@ func ExportKeyCommand() *cobra.Command { Short: "Export private keys", Long: `Export a private key from the local keybase in ASCII-armored encrypted format.`, Args: cobra.ExactArgs(1), - RunE: runExportCmd, + RunE: func(cmd *cobra.Command, args []string) error { + buf := bufio.NewReader(cmd.InOrStdin()) + + backend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend) + homeDir, _ := cmd.Flags().GetString(flags.FlagHome) + kb, err := keyring.New(sdk.KeyringServiceName(), backend, homeDir, buf) + if err != nil { + return err + } + + encryptPassword, err := input.GetPassword("Enter passphrase to encrypt the exported key:", buf) + if err != nil { + return err + } + + armored, err := kb.ExportPrivKeyArmor(args[0], encryptPassword) + if err != nil { + return err + } + + cmd.Println(armored) + return nil + }, } } - -func runExportCmd(cmd *cobra.Command, args []string) error { - buf := bufio.NewReader(cmd.InOrStdin()) - kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) - if err != nil { - return err - } - - encryptPassword, err := input.GetPassword("Enter passphrase to encrypt the exported key:", buf) - if err != nil { - return err - } - - armored, err := kb.ExportPrivKeyArmor(args[0], encryptPassword) - if err != nil { - return err - } - - cmd.Println(armored) - return nil -} diff --git a/client/keys/export_test.go b/client/keys/export_test.go index 99262ceaa9..9375824359 100644 --- a/client/keys/export_test.go +++ b/client/keys/export_test.go @@ -1,9 +1,9 @@ package keys import ( + "fmt" "testing" - "github.com/spf13/viper" "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/crypto/hd" @@ -15,16 +15,16 @@ import ( ) func Test_runExportCmd(t *testing.T) { - exportKeyCommand := ExportKeyCommand() - mockIn, _, _ := tests.ApplyMockIO(exportKeyCommand) + cmd := ExportKeyCommand() + cmd.Flags().AddFlagSet(Commands().PersistentFlags()) + mockIn, _, _ := tests.ApplyMockIO(cmd) // Now add a temporary keybase kbHome, cleanUp := tests.NewTestCaseDir(t) t.Cleanup(cleanUp) - viper.Set(flags.FlagHome, kbHome) // create a key - kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) + kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn) require.NoError(t, err) t.Cleanup(func() { kb.Delete("keyname1") // nolint:errcheck @@ -36,5 +36,11 @@ func Test_runExportCmd(t *testing.T) { // Now enter password mockIn.Reset("123456789\n123456789\n") - require.NoError(t, runExportCmd(exportKeyCommand, []string{"keyname1"})) + cmd.SetArgs([]string{ + "keyname1", + fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + }) + + require.NoError(t, cmd.Execute()) } diff --git a/client/keys/import.go b/client/keys/import.go index cbba4598dc..641ac6ef62 100644 --- a/client/keys/import.go +++ b/client/keys/import.go @@ -5,7 +5,6 @@ import ( "io/ioutil" "github.com/spf13/cobra" - "github.com/spf13/viper" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/input" @@ -20,26 +19,27 @@ func ImportKeyCommand() *cobra.Command { Short: "Import private keys into the local keybase", Long: "Import a ASCII armored private key into the local keybase.", Args: cobra.ExactArgs(2), - RunE: runImportCmd, + RunE: func(cmd *cobra.Command, args []string) error { + buf := bufio.NewReader(cmd.InOrStdin()) + + backend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend) + homeDir, _ := cmd.Flags().GetString(flags.FlagHome) + kb, err := keyring.New(sdk.KeyringServiceName(), backend, homeDir, buf) + if err != nil { + return err + } + + bz, err := ioutil.ReadFile(args[1]) + if err != nil { + return err + } + + passphrase, err := input.GetPassword("Enter passphrase to decrypt your key:", buf) + if err != nil { + return err + } + + return kb.ImportPrivKey(args[0], string(bz), passphrase) + }, } } - -func runImportCmd(cmd *cobra.Command, args []string) error { - buf := bufio.NewReader(cmd.InOrStdin()) - kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), buf) - if err != nil { - return err - } - - bz, err := ioutil.ReadFile(args[1]) - if err != nil { - return err - } - - passphrase, err := input.GetPassword("Enter passphrase to decrypt your key:", buf) - if err != nil { - return err - } - - return kb.ImportPrivKey(args[0], string(bz), passphrase) -} diff --git a/client/keys/import_test.go b/client/keys/import_test.go index 6451277d3e..88de08be6b 100644 --- a/client/keys/import_test.go +++ b/client/keys/import_test.go @@ -1,11 +1,11 @@ package keys import ( + "fmt" "io/ioutil" "path/filepath" "testing" - "github.com/spf13/viper" "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/client/flags" @@ -15,15 +15,15 @@ import ( ) func Test_runImportCmd(t *testing.T) { - importKeyCommand := ImportKeyCommand() - mockIn, _, _ := tests.ApplyMockIO(importKeyCommand) + cmd := ImportKeyCommand() + cmd.Flags().AddFlagSet(Commands().PersistentFlags()) + mockIn, _, _ := tests.ApplyMockIO(cmd) // Now add a temporary keybase kbHome, cleanUp := tests.NewTestCaseDir(t) t.Cleanup(cleanUp) - viper.Set(flags.FlagHome, kbHome) - kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), kbHome, mockIn) + kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn) require.NoError(t, err) t.Cleanup(func() { kb.Delete("keyname1") // nolint:errcheck @@ -41,7 +41,11 @@ HbP+c6JmeJy9JXe2rbbF1QtCX1gLqGcDQPBXiCtFvP7/8wTZtVOPj8vREzhZ9ElO ` require.NoError(t, ioutil.WriteFile(keyfile, []byte(armoredKey), 0644)) - // Now enter password mockIn.Reset("123456789\n") - require.NoError(t, runImportCmd(importKeyCommand, []string{"keyname1", keyfile})) + cmd.SetArgs([]string{ + "keyname1", keyfile, + fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + }) + require.NoError(t, cmd.Execute()) } diff --git a/client/keys/list.go b/client/keys/list.go index 4862fccf87..0c6eedab26 100644 --- a/client/keys/list.go +++ b/client/keys/list.go @@ -2,7 +2,7 @@ package keys import ( "github.com/spf13/cobra" - "github.com/spf13/viper" + "github.com/tendermint/tendermint/libs/cli" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/crypto/keyring" @@ -26,7 +26,9 @@ along with their associated name and address.`, } func runListCmd(cmd *cobra.Command, _ []string) error { - kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), cmd.InOrStdin()) + backend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend) + homeDir, _ := cmd.Flags().GetString(flags.FlagHome) + kb, err := keyring.New(sdk.KeyringServiceName(), backend, homeDir, cmd.InOrStdin()) if err != nil { return err } @@ -37,8 +39,10 @@ func runListCmd(cmd *cobra.Command, _ []string) error { } cmd.SetOut(cmd.OutOrStdout()) - if !viper.GetBool(flagListNames) { - printInfos(cmd.OutOrStdout(), infos) + + if ok, _ := cmd.Flags().GetBool(flagListNames); !ok { + output, _ := cmd.Flags().GetString(cli.OutputFlag) + printInfos(cmd.OutOrStdout(), infos, output) return nil } diff --git a/client/keys/list_test.go b/client/keys/list_test.go index 849ac9b8d8..ad0bcafa98 100644 --- a/client/keys/list_test.go +++ b/client/keys/list_test.go @@ -1,39 +1,31 @@ package keys import ( + "fmt" "testing" "github.com/spf13/cobra" - "github.com/spf13/viper" "github.com/stretchr/testify/require" - "github.com/cosmos/cosmos-sdk/crypto/hd" - "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" ) func Test_runListCmd(t *testing.T) { - type args struct { - cmd *cobra.Command - args []string - } + cmd := ListKeysCmd() + cmd.Flags().AddFlagSet(Commands().PersistentFlags()) - cmdBasic := ListKeysCmd() - - // Prepare some keybases kbHome1, cleanUp1 := tests.NewTestCaseDir(t) t.Cleanup(cleanUp1) - // Do nothing, leave home1 empty kbHome2, cleanUp2 := tests.NewTestCaseDir(t) t.Cleanup(cleanUp2) - viper.Set(flags.FlagHome, kbHome2) - mockIn, _, _ := tests.ApplyMockIO(cmdBasic) - kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) + mockIn, _, _ := tests.ApplyMockIO(cmd) + kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome2, mockIn) require.NoError(t, err) path := "" //sdk.GetConfig().GetFullFundraiserPath() @@ -42,28 +34,41 @@ func Test_runListCmd(t *testing.T) { t.Cleanup(func() { kb.Delete("something") // nolint:errcheck - }) + + type args struct { + cmd *cobra.Command + args []string + } + testData := []struct { name string kbDir string - args args wantErr bool }{ - {"keybase: empty", kbHome1, args{cmdBasic, []string{}}, false}, - {"keybase: w/key", kbHome2, args{cmdBasic, []string{}}, false}, + {"keybase: empty", kbHome1, false}, + {"keybase: w/key", kbHome2, false}, } for _, tt := range testData { tt := tt t.Run(tt.name, func(t *testing.T) { - viper.Set(flagListNames, false) - viper.Set(flags.FlagHome, tt.kbDir) - if err := runListCmd(tt.args.cmd, tt.args.args); (err != nil) != tt.wantErr { + cmd.SetArgs([]string{ + fmt.Sprintf("--%s=%s", flags.FlagHome, tt.kbDir), + fmt.Sprintf("--%s=false", flagListNames), + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + }) + + if err := cmd.Execute(); (err != nil) != tt.wantErr { t.Errorf("runListCmd() error = %v, wantErr %v", err, tt.wantErr) } - viper.Set(flagListNames, true) - if err := runListCmd(tt.args.cmd, tt.args.args); (err != nil) != tt.wantErr { + cmd.SetArgs([]string{ + fmt.Sprintf("--%s=%s", flags.FlagHome, tt.kbDir), + fmt.Sprintf("--%s=true", flagListNames), + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + }) + + if err := cmd.Execute(); (err != nil) != tt.wantErr { t.Errorf("runListCmd() error = %v, wantErr %v", err, tt.wantErr) } }) diff --git a/client/keys/migrate.go b/client/keys/migrate.go index 8d52bd83fa..d80bbe1630 100644 --- a/client/keys/migrate.go +++ b/client/keys/migrate.go @@ -6,14 +6,13 @@ import ( "io/ioutil" "os" + "github.com/pkg/errors" + "github.com/spf13/cobra" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/input" "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/pkg/errors" - "github.com/spf13/cobra" - "github.com/spf13/viper" ) // migratePassphrase is used as a no-op migration key passphrase as a passphrase @@ -41,13 +40,15 @@ It is recommended to run in 'dry-run' mode first to verify all key migration mat } func runMigrateCmd(cmd *cobra.Command, args []string) error { + rootDir, _ := cmd.Flags().GetString(flags.FlagHome) + // instantiate legacy keybase - rootDir := viper.GetString(flags.FlagHome) var legacyKb keyring.LegacyKeybase legacyKb, err := NewLegacyKeyBaseFromDir(rootDir) if err != nil { return err } + defer legacyKb.Close() // fetch list of keys from legacy keybase @@ -64,7 +65,7 @@ func runMigrateCmd(cmd *cobra.Command, args []string) error { migrator keyring.InfoImporter ) - if viper.GetBool(flags.FlagDryRun) { + if dryRun, _ := cmd.Flags().GetBool(flags.FlagDryRun); dryRun { tmpDir, err = ioutil.TempDir("", "migrator-migrate-dryrun") if err != nil { return errors.Wrap(err, "failed to create temporary directory for dryrun migration") @@ -74,8 +75,10 @@ func runMigrateCmd(cmd *cobra.Command, args []string) error { migrator, err = keyring.NewInfoImporter(keyringServiceName, "test", tmpDir, buf) } else { - migrator, err = keyring.NewInfoImporter(keyringServiceName, viper.GetString(flags.FlagKeyringBackend), rootDir, buf) + backend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend) + migrator, err = keyring.NewInfoImporter(keyringServiceName, backend, rootDir, buf) } + if err != nil { return errors.Wrap(err, fmt.Sprintf( "failed to initialize keybase for service %s at directory %s", diff --git a/client/keys/migrate_test.go b/client/keys/migrate_test.go index 6f24a6387d..6f36bfc9f4 100644 --- a/client/keys/migrate_test.go +++ b/client/keys/migrate_test.go @@ -1,36 +1,48 @@ package keys import ( + "fmt" + "io/ioutil" "testing" "github.com/otiai10/copy" + "github.com/stretchr/testify/assert" + "github.com/tendermint/tendermint/libs/cli" "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/tests" - - "github.com/spf13/viper" - "github.com/stretchr/testify/assert" - - "github.com/tendermint/tendermint/libs/cli" ) func Test_runMigrateCmd(t *testing.T) { cmd := AddKeyCommand() - assert.NotNil(t, cmd) + cmd.SetErr(ioutil.Discard) + cmd.SetOut(ioutil.Discard) + cmd.Flags().AddFlagSet(Commands().PersistentFlags()) kbHome, kbCleanUp := tests.NewTestCaseDir(t) copy.Copy("testdata", kbHome) assert.NotNil(t, kbHome) t.Cleanup(kbCleanUp) - viper.Set(flags.FlagHome, kbHome) - viper.Set(cli.OutputFlag, OutputFormatText) + cmd.SetArgs([]string{ + "keyname1", + fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), + fmt.Sprintf("--%s=%s", cli.OutputFlag, OutputFormatText), + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + }) + assert.NoError(t, cmd.Execute()) - assert.NoError(t, runAddCmd(cmd, []string{"keyname1"})) - - viper.Set(flags.FlagDryRun, true) cmd = MigrateCommand() + cmd.Flags().AddFlagSet(Commands().PersistentFlags()) mockIn, _, _ := tests.ApplyMockIO(cmd) + + cmd.SetArgs([]string{ + fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), + fmt.Sprintf("--%s=true", flags.FlagDryRun), + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + }) + mockIn.Reset("test1234\ntest1234\n") - assert.NoError(t, runMigrateCmd(cmd, []string{})) + assert.NoError(t, cmd.Execute()) } diff --git a/client/keys/mnemonic.go b/client/keys/mnemonic.go index 66b3b17d02..c411612782 100644 --- a/client/keys/mnemonic.go +++ b/client/keys/mnemonic.go @@ -23,54 +23,53 @@ func MnemonicKeyCommand() *cobra.Command { Use: "mnemonic", Short: "Compute the bip39 mnemonic for some input entropy", Long: "Create a bip39 mnemonic, sometimes called a seed phrase, by reading from the system entropy. To pass your own entropy, use --unsafe-entropy", - RunE: runMnemonicCmd, + RunE: func(cmd *cobra.Command, args []string) error { + var entropySeed []byte + + if userEntropy, _ := cmd.Flags().GetBool(flagUserEntropy); userEntropy { + // prompt the user to enter some entropy + buf := bufio.NewReader(cmd.InOrStdin()) + + inputEntropy, err := input.GetString("> WARNING: Generate at least 256-bits of entropy and enter the results here:", buf) + if err != nil { + return err + } + + if len(inputEntropy) < 43 { + return fmt.Errorf("256-bits is 43 characters in Base-64, and 100 in Base-6. You entered %v, and probably want more", len(inputEntropy)) + } + + conf, err := input.GetConfirmation(fmt.Sprintf("> Input length: %d", len(inputEntropy)), buf, cmd.ErrOrStderr()) + if err != nil { + return err + } + + if !conf { + return nil + } + + // hash input entropy to get entropy seed + hashedEntropy := sha256.Sum256([]byte(inputEntropy)) + entropySeed = hashedEntropy[:] + } else { + // read entropy seed straight from crypto.Rand + var err error + entropySeed, err = bip39.NewEntropy(mnemonicEntropySize) + if err != nil { + return err + } + } + + mnemonic, err := bip39.NewMnemonic(entropySeed) + if err != nil { + return err + } + + cmd.Println(mnemonic) + return nil + }, } + cmd.Flags().Bool(flagUserEntropy, false, "Prompt the user to supply their own entropy, instead of relying on the system") return cmd } - -func runMnemonicCmd(cmd *cobra.Command, args []string) error { - flags := cmd.Flags() - - userEntropy, _ := flags.GetBool(flagUserEntropy) - - var entropySeed []byte - - if userEntropy { - // prompt the user to enter some entropy - buf := bufio.NewReader(cmd.InOrStdin()) - inputEntropy, err := input.GetString("> WARNING: Generate at least 256-bits of entropy and enter the results here:", buf) - if err != nil { - return err - } - if len(inputEntropy) < 43 { - return fmt.Errorf("256-bits is 43 characters in Base-64, and 100 in Base-6. You entered %v, and probably want more", len(inputEntropy)) - } - conf, err := input.GetConfirmation(fmt.Sprintf("> Input length: %d", len(inputEntropy)), buf, cmd.ErrOrStderr()) - if err != nil { - return err - } - if !conf { - return nil - } - - // hash input entropy to get entropy seed - hashedEntropy := sha256.Sum256([]byte(inputEntropy)) - entropySeed = hashedEntropy[:] - } else { - // read entropy seed straight from crypto.Rand - var err error - entropySeed, err = bip39.NewEntropy(mnemonicEntropySize) - if err != nil { - return err - } - } - - mnemonic, err := bip39.NewMnemonic(entropySeed) - if err != nil { - return err - } - cmd.Println(mnemonic) - - return nil -} diff --git a/client/keys/mnemonic_test.go b/client/keys/mnemonic_test.go index a3e84e7182..c333657f96 100644 --- a/client/keys/mnemonic_test.go +++ b/client/keys/mnemonic_test.go @@ -1,33 +1,38 @@ package keys import ( + "fmt" + "io/ioutil" "strings" "testing" - "github.com/cosmos/cosmos-sdk/tests" - - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/tests" ) func Test_RunMnemonicCmdNormal(t *testing.T) { - cmdBasic := MnemonicKeyCommand() - require.NoError(t, runMnemonicCmd(cmdBasic, []string{})) + cmd := MnemonicKeyCommand() + cmd.SetErr(ioutil.Discard) + cmd.SetOut(ioutil.Discard) + cmd.SetArgs([]string{}) + require.NoError(t, cmd.Execute()) } func Test_RunMnemonicCmdUser(t *testing.T) { - cmdUser := MnemonicKeyCommand() - err := cmdUser.Flags().Set(flagUserEntropy, "1") - assert.NoError(t, err) + cmd := MnemonicKeyCommand() + cmd.SetErr(ioutil.Discard) + cmd.SetOut(ioutil.Discard) - err = runMnemonicCmd(cmdUser, []string{}) + cmd.SetArgs([]string{fmt.Sprintf("--%s=1", flagUserEntropy)}) + err := cmd.Execute() require.Error(t, err) require.Equal(t, "EOF", err.Error()) // Try again - mockIn, _, _ := tests.ApplyMockIO(cmdUser) + mockIn, _, _ := tests.ApplyMockIO(cmd) mockIn.Reset("Hi!\n") - err = runMnemonicCmd(cmdUser, []string{}) + err = cmd.Execute() require.Error(t, err) require.Equal(t, "256-bits is 43 characters in Base-64, and 100 in Base-6. You entered 3, and probably want more", @@ -36,15 +41,15 @@ func Test_RunMnemonicCmdUser(t *testing.T) { // Now provide "good" entropy :) fakeEntropy := strings.Repeat(":)", 40) + "\ny\n" // entropy + accept count mockIn.Reset(fakeEntropy) - require.NoError(t, runMnemonicCmd(cmdUser, []string{})) + require.NoError(t, cmd.Execute()) // Now provide "good" entropy but no answer fakeEntropy = strings.Repeat(":)", 40) + "\n" // entropy + accept count mockIn.Reset(fakeEntropy) - require.Error(t, runMnemonicCmd(cmdUser, []string{})) + require.Error(t, cmd.Execute()) // Now provide "good" entropy but say no fakeEntropy = strings.Repeat(":)", 40) + "\nn\n" // entropy + accept count mockIn.Reset(fakeEntropy) - require.NoError(t, runMnemonicCmd(cmdUser, []string{})) + require.NoError(t, cmd.Execute()) } diff --git a/client/keys/parse.go b/client/keys/parse.go index 47424e58e5..2af792c03c 100644 --- a/client/keys/parse.go +++ b/client/keys/parse.go @@ -9,14 +9,11 @@ import ( "strings" "github.com/spf13/cobra" - "github.com/spf13/viper" + "github.com/tendermint/tendermint/libs/cli" yaml "gopkg.in/yaml.v2" - "github.com/tendermint/tendermint/libs/cli" - - "github.com/cosmos/cosmos-sdk/types/bech32" - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/bech32" ) func bech32Prefixes(config *sdk.Config) []string { @@ -101,7 +98,8 @@ func doParseKey(cmd *cobra.Command, config *sdk.Config, args []string) error { return errors.New("couldn't parse empty input") } - if !(runFromBech32(outstream, addr) || runFromHex(config, outstream, addr)) { + output, _ := cmd.Flags().GetString(cli.OutputFlag) + if !(runFromBech32(outstream, addr, output) || runFromHex(config, outstream, addr, output)) { return errors.New("couldn't find valid bech32 nor hex data") } @@ -109,36 +107,36 @@ func doParseKey(cmd *cobra.Command, config *sdk.Config, args []string) error { } // print info from bech32 -func runFromBech32(w io.Writer, bech32str string) bool { +func runFromBech32(w io.Writer, bech32str, output string) bool { hrp, bz, err := bech32.DecodeAndConvert(bech32str) if err != nil { return false } - displayParseKeyInfo(w, newHexOutput(hrp, bz)) + displayParseKeyInfo(w, newHexOutput(hrp, bz), output) return true } // print info from hex -func runFromHex(config *sdk.Config, w io.Writer, hexstr string) bool { +func runFromHex(config *sdk.Config, w io.Writer, hexstr, output string) bool { bz, err := hex.DecodeString(hexstr) if err != nil { return false } - displayParseKeyInfo(w, newBech32Output(config, bz)) + displayParseKeyInfo(w, newBech32Output(config, bz), output) return true } -func displayParseKeyInfo(w io.Writer, stringer fmt.Stringer) { +func displayParseKeyInfo(w io.Writer, stringer fmt.Stringer, output string) { var ( err error out []byte ) - switch viper.Get(cli.OutputFlag) { + switch output { case OutputFormatText: out, err = yaml.Marshal(&stringer) diff --git a/client/keys/root.go b/client/keys/root.go index 801cc065ae..98bb616867 100644 --- a/client/keys/root.go +++ b/client/keys/root.go @@ -2,7 +2,7 @@ package keys import ( "github.com/spf13/cobra" - "github.com/spf13/viper" + "github.com/tendermint/tendermint/libs/cli" "github.com/cosmos/cosmos-sdk/client/flags" ) @@ -36,6 +36,7 @@ information: The pass backend requires GnuPG: https://gnupg.org/ `, } + cmd.AddCommand( MnemonicKeyCommand(), AddKeyCommand(), @@ -48,7 +49,10 @@ The pass backend requires GnuPG: https://gnupg.org/ ParseKeyStringCommand(), MigrateCommand(), ) + + cmd.PersistentFlags().String(flags.FlagHome, "", "The application home directory") cmd.PersistentFlags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|test)") - viper.BindPFlag(flags.FlagKeyringBackend, cmd.Flags().Lookup(flags.FlagKeyringBackend)) + cmd.PersistentFlags().String(cli.OutputFlag, "text", "Output format (text|json)") + return cmd } diff --git a/client/keys/root_test.go b/client/keys/root_test.go index e995da9796..6a81d0c12a 100644 --- a/client/keys/root_test.go +++ b/client/keys/root_test.go @@ -1,15 +1,9 @@ package keys import ( - "os" "testing" - "github.com/spf13/viper" "github.com/stretchr/testify/assert" - - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/crypto/keyring" - sdk "github.com/cosmos/cosmos-sdk/types" ) func TestCommands(t *testing.T) { @@ -19,9 +13,3 @@ func TestCommands(t *testing.T) { // Commands are registered assert.Equal(t, 10, len(rootCommands.Commands())) } - -func TestMain(m *testing.M) { - viper.Set(flags.FlagKeyringBackend, keyring.BackendTest) - viper.Set(flagCoinType, sdk.CoinType) - os.Exit(m.Run()) -} diff --git a/client/keys/show.go b/client/keys/show.go index 1d38fe4232..10559f407f 100644 --- a/client/keys/show.go +++ b/client/keys/show.go @@ -5,8 +5,6 @@ import ( "fmt" "github.com/spf13/cobra" - "github.com/spf13/viper" - tmcrypto "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/libs/cli" @@ -48,7 +46,7 @@ consisting of all the keys provided by name and multisig threshold.`, cmd.Flags().BoolP(FlagAddress, "a", false, "Output the address only (overrides --output)") cmd.Flags().BoolP(FlagPublicKey, "p", false, "Output the public key only (overrides --output)") cmd.Flags().BoolP(FlagDevice, "d", false, "Output the address in a ledger device") - cmd.Flags().Uint(flagMultiSigThreshold, 1, "K out of N required signatures") + cmd.Flags().Int(flagMultiSigThreshold, 1, "K out of N required signatures") return cmd } @@ -56,10 +54,13 @@ consisting of all the keys provided by name and multisig threshold.`, func runShowCmd(cmd *cobra.Command, args []string) (err error) { var info keyring.Info - kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), cmd.InOrStdin()) + backend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend) + homeDir, _ := cmd.Flags().GetString(flags.FlagHome) + kb, err := keyring.New(sdk.KeyringServiceName(), backend, homeDir, cmd.InOrStdin()) if err != nil { return err } + if len(args) == 1 { info, err = fetchKey(kb, args[0]) if err != nil { @@ -76,7 +77,7 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) { pks[i] = info.GetPubKey() } - multisigThreshold := viper.GetInt(flagMultiSigThreshold) + multisigThreshold, _ := cmd.Flags().GetInt(flagMultiSigThreshold) err = validateMultisigThreshold(multisigThreshold, len(args)) if err != nil { return err @@ -86,9 +87,9 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) { info = keyring.NewMultiInfo(defaultMultiSigKeyName, multikey) } - isShowAddr := viper.GetBool(FlagAddress) - isShowPubKey := viper.GetBool(FlagPublicKey) - isShowDevice := viper.GetBool(FlagDevice) + isShowAddr, _ := cmd.Flags().GetBool(FlagAddress) + isShowPubKey, _ := cmd.Flags().GetBool(FlagPublicKey) + isShowDevice, _ := cmd.Flags().GetBool(FlagDevice) isOutputSet := false tmp := cmd.Flag(cli.OutputFlag) @@ -104,27 +105,31 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) { return errors.New("cannot use --output with --address or --pubkey") } - bechKeyOut, err := getBechKeyOut(viper.GetString(FlagBechPrefix)) + bechPrefix, _ := cmd.Flags().GetString(FlagBechPrefix) + bechKeyOut, err := getBechKeyOut(bechPrefix) if err != nil { return err } + output, _ := cmd.Flags().GetString(cli.OutputFlag) + switch { case isShowAddr: printKeyAddress(cmd.OutOrStdout(), info, bechKeyOut) case isShowPubKey: printPubKey(cmd.OutOrStdout(), info, bechKeyOut) default: - printKeyInfo(cmd.OutOrStdout(), info, bechKeyOut) + printKeyInfo(cmd.OutOrStdout(), info, bechKeyOut, output) } if isShowDevice { if isShowPubKey { return fmt.Errorf("the device flag (-d) can only be used for addresses not pubkeys") } - if viper.GetString(FlagBechPrefix) != "acc" { + if bechPrefix != "acc" { return fmt.Errorf("the device flag (-d) can only be used for accounts") } + // Override and show in the device if info.GetType() != keyring.TypeLedger { return fmt.Errorf("the device flag (-d) can only be used for accounts stored in devices") diff --git a/client/keys/show_test.go b/client/keys/show_test.go index 079e56b4a7..abc6d1de5b 100644 --- a/client/keys/show_test.go +++ b/client/keys/show_test.go @@ -1,9 +1,9 @@ package keys import ( + "fmt" "testing" - "github.com/spf13/viper" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto" @@ -37,19 +37,22 @@ func Test_showKeysCmd(t *testing.T) { func Test_runShowCmd(t *testing.T) { cmd := ShowKeysCmd() + cmd.Flags().AddFlagSet(Commands().PersistentFlags()) mockIn, _, _ := tests.ApplyMockIO(cmd) - require.EqualError(t, runShowCmd(cmd, []string{"invalid"}), "invalid is not a valid name or address: decoding bech32 failed: invalid bech32 string length 7") - require.EqualError(t, runShowCmd(cmd, []string{"invalid1", "invalid2"}), "invalid1 is not a valid name or address: decoding bech32 failed: invalid index of 1") - // Prepare a key base - // Now add a temporary keybase + cmd.SetArgs([]string{"invalid"}) + require.EqualError(t, cmd.Execute(), "invalid is not a valid name or address: decoding bech32 failed: invalid bech32 string length 7") + + cmd.SetArgs([]string{"invalid1", "invalid2"}) + require.EqualError(t, cmd.Execute(), "invalid1 is not a valid name or address: decoding bech32 failed: invalid index of 1") + kbHome, cleanUp := tests.NewTestCaseDir(t) t.Cleanup(cleanUp) - viper.Set(flags.FlagHome, kbHome) fakeKeyName1 := "runShowCmd_Key1" fakeKeyName2 := "runShowCmd_Key2" - kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), mockIn) + + kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn) require.NoError(t, err) t.Cleanup(func() { kb.Delete("runShowCmd_Key1") @@ -65,44 +68,86 @@ func Test_runShowCmd(t *testing.T) { require.NoError(t, err) // Now try single key - require.EqualError(t, runShowCmd(cmd, []string{fakeKeyName1}), "invalid Bech32 prefix encoding provided: ") + cmd.SetArgs([]string{ + fakeKeyName1, + fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + fmt.Sprintf("--%s=", FlagBechPrefix), + }) + require.EqualError(t, cmd.Execute(), "invalid Bech32 prefix encoding provided: ") - // Now try single key - set bech to acc - viper.Set(FlagBechPrefix, sdk.PrefixAccount) + cmd.SetArgs([]string{ + fakeKeyName1, + fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + fmt.Sprintf("--%s=%s", FlagBechPrefix, sdk.PrefixAccount), + }) // try fetch by name - require.NoError(t, runShowCmd(cmd, []string{fakeKeyName1})) + require.NoError(t, cmd.Execute()) + // try fetch by addr info, err := kb.Key(fakeKeyName1) + cmd.SetArgs([]string{ + info.GetAddress().String(), + fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + fmt.Sprintf("--%s=%s", FlagBechPrefix, sdk.PrefixAccount), + }) + require.NoError(t, err) - require.NoError(t, runShowCmd(cmd, []string{info.GetAddress().String()})) + require.NoError(t, cmd.Execute()) // Now try multisig key - set bech to acc - viper.Set(FlagBechPrefix, sdk.PrefixAccount) - require.EqualError(t, runShowCmd(cmd, []string{fakeKeyName1, fakeKeyName2}), "threshold must be a positive integer") + cmd.SetArgs([]string{ + fakeKeyName1, fakeKeyName2, + fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + fmt.Sprintf("--%s=%s", FlagBechPrefix, sdk.PrefixAccount), + fmt.Sprintf("--%s=0", flagMultiSigThreshold), + }) + require.EqualError(t, cmd.Execute(), "threshold must be a positive integer") + + cmd.SetArgs([]string{ + fakeKeyName1, fakeKeyName2, + fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + fmt.Sprintf("--%s=%s", FlagBechPrefix, sdk.PrefixAccount), + fmt.Sprintf("--%s=2", flagMultiSigThreshold), + }) + require.NoError(t, cmd.Execute()) // Now try multisig key - set bech to acc + threshold=2 - viper.Set(FlagBechPrefix, sdk.PrefixAccount) - viper.Set(flagMultiSigThreshold, 2) - err = runShowCmd(cmd, []string{fakeKeyName1, fakeKeyName2}) - require.NoError(t, err) + cmd.SetArgs([]string{ + fakeKeyName1, fakeKeyName2, + fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + fmt.Sprintf("--%s=acc", FlagBechPrefix), + fmt.Sprintf("--%s=true", FlagDevice), + fmt.Sprintf("--%s=2", flagMultiSigThreshold), + }) + require.EqualError(t, cmd.Execute(), "the device flag (-d) can only be used for accounts stored in devices") - // Now try multisig key - set bech to acc + threshold=2 - viper.Set(FlagBechPrefix, "acc") - viper.Set(FlagDevice, true) - viper.Set(flagMultiSigThreshold, 2) - err = runShowCmd(cmd, []string{fakeKeyName1, fakeKeyName2}) - require.EqualError(t, err, "the device flag (-d) can only be used for accounts stored in devices") + cmd.SetArgs([]string{ + fakeKeyName1, fakeKeyName2, + fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + fmt.Sprintf("--%s=val", FlagBechPrefix), + fmt.Sprintf("--%s=true", FlagDevice), + fmt.Sprintf("--%s=2", flagMultiSigThreshold), + }) + require.EqualError(t, cmd.Execute(), "the device flag (-d) can only be used for accounts") - viper.Set(FlagBechPrefix, "val") - err = runShowCmd(cmd, []string{fakeKeyName1, fakeKeyName2}) - require.EqualError(t, err, "the device flag (-d) can only be used for accounts") - - viper.Set(FlagPublicKey, true) - err = runShowCmd(cmd, []string{fakeKeyName1, fakeKeyName2}) - require.EqualError(t, err, "the device flag (-d) can only be used for addresses not pubkeys") - - // TODO: Capture stdout and compare + cmd.SetArgs([]string{ + fakeKeyName1, fakeKeyName2, + fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + fmt.Sprintf("--%s=val", FlagBechPrefix), + fmt.Sprintf("--%s=true", FlagDevice), + fmt.Sprintf("--%s=2", flagMultiSigThreshold), + fmt.Sprintf("--%s=true", FlagPublicKey), + }) + require.EqualError(t, cmd.Execute(), "the device flag (-d) can only be used for addresses not pubkeys") } func Test_validateMultisigThreshold(t *testing.T) { diff --git a/client/keys/utils.go b/client/keys/utils.go index 69f3de80dd..891ddeaeb9 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -5,8 +5,6 @@ import ( "io" "path/filepath" - "github.com/spf13/viper" - "github.com/tendermint/tendermint/libs/cli" "gopkg.in/yaml.v2" cryptokeyring "github.com/cosmos/cosmos-sdk/crypto/keyring" @@ -33,13 +31,13 @@ func getLegacyKeyBaseFromDir(rootDir string, opts ...cryptokeyring.KeybaseOption return cryptokeyring.NewLegacy(defaultKeyDBName, filepath.Join(rootDir, "keys"), opts...) } -func printKeyInfo(w io.Writer, keyInfo cryptokeyring.Info, bechKeyOut bechKeyOutFn) { +func printKeyInfo(w io.Writer, keyInfo cryptokeyring.Info, bechKeyOut bechKeyOutFn, output string) { ko, err := bechKeyOut(keyInfo) if err != nil { panic(err) } - switch viper.Get(cli.OutputFlag) { + switch output { case OutputFormatText: printTextInfos(w, []cryptokeyring.KeyOutput{ko}) @@ -53,13 +51,13 @@ func printKeyInfo(w io.Writer, keyInfo cryptokeyring.Info, bechKeyOut bechKeyOut } } -func printInfos(w io.Writer, infos []cryptokeyring.Info) { +func printInfos(w io.Writer, infos []cryptokeyring.Info, output string) { kos, err := cryptokeyring.Bech32KeysOutput(infos) if err != nil { panic(err) } - switch viper.Get(cli.OutputFlag) { + switch output { case OutputFormatText: printTextInfos(w, kos)