diff --git a/CHANGELOG.md b/CHANGELOG.md index b5215f9e80..28b8a59130 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,6 +56,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements +* (client/keys) [#18745](https://github.com/cosmos/cosmos-sdk/pull/18745) Improve ` keys export` and ` keys mnemonic` by adding --yes option to skip interactive confirmation. * (x/bank) [#24106](https://github.com/cosmos/cosmos-sdk/pull/24106) `SendCoins` now checks for `SendRestrictions` before instead of after deducting coins using `subUnlockedCoins`. * (crypto/ledger) [#24036](https://github.com/cosmos/cosmos-sdk/pull/24036) Improve error message when deriving paths using index > 100 * (gRPC) [#23844](https://github.com/cosmos/cosmos-sdk/pull/23844) Add debug log prints for each gRPC request. @@ -63,7 +64,6 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (server) [#24072](https://github.com/cosmos/cosmos-sdk/pull/24072) Return BlockHeader by shallow copy in server Context. * (x/bank) [#24053](https://github.com/cosmos/cosmos-sdk/pull/24053) Resolve a foot-gun by swapping send restrictions check in `InputOutputCoins` before coin deduction. - ### Bug Fixes * (server) [#24068](https://github.com/cosmos/cosmos-sdk/pull/24068) Allow align block header with skip check header in grpc server. diff --git a/client/keys/export.go b/client/keys/export.go index 7e2f7250d3..5536520e0a 100644 --- a/client/keys/export.go +++ b/client/keys/export.go @@ -65,16 +65,19 @@ and export your keys in ASCII-armored encrypted format.`, cmd.Flags().Bool(flagUnarmoredHex, false, "Export unarmored hex privkey. Requires --unsafe.") cmd.Flags().Bool(flagUnsafe, false, "Enable unsafe operations. This flag must be switched on along with all unsafe operation-specific options.") + cmd.Flags().BoolP(flagYes, "y", false, "Skip confirmation prompt when export unarmored hex privkey") return cmd } func exportUnsafeUnarmored(cmd *cobra.Command, uid string, buf *bufio.Reader, kr keyring.Keyring) error { - // confirm deletion, unless -y is passed - if yes, err := input.GetConfirmation("WARNING: The private key will be exported as an unarmored hexadecimal string. USE AT YOUR OWN RISK. Continue?", buf, cmd.ErrOrStderr()); err != nil { - return err - } else if !yes { - return nil + // confirm export unarmored hex privkey, unless -y is passed + if skip, _ := cmd.Flags().GetBool(flagYes); !skip { + if yes, err := input.GetConfirmation("WARNING: The private key will be exported as an unarmored hexadecimal string. USE AT YOUR OWN RISK. Continue?", buf, cmd.ErrOrStderr()); err != nil { + return err + } else if !yes { + return nil + } } hexPrivKey, err := unsafeExportPrivKeyHex(kr.(unsafeExporter), uid) diff --git a/client/keys/export_test.go b/client/keys/export_test.go index d7e4126f6a..564c2aee4d 100644 --- a/client/keys/export_test.go +++ b/client/keys/export_test.go @@ -21,12 +21,13 @@ import ( func Test_runExportCmd(t *testing.T) { cdc := moduletestutil.MakeTestEncodingConfig().Codec testCases := []struct { - name string - keyringBackend string - extraArgs []string - userInput string - mustFail bool - expectedOutput string + name string + keyringBackend string + extraArgs []string + userInput string + mustFail bool + expectedOutput string + expectedOutputContain string }{ { name: "--unsafe only must fail", @@ -49,12 +50,20 @@ func Test_runExportCmd(t *testing.T) { expectedOutput: "", }, { - name: "--unsafe --unarmored-hex succeed", - keyringBackend: keyring.BackendTest, - extraArgs: []string{"--unsafe", "--unarmored-hex"}, - userInput: "y\n", - mustFail: false, - expectedOutput: "2485e33678db4175dc0ecef2d6e1fc493d4a0d7f7ce83324b6ed70afe77f3485\n", + name: "--unsafe --unarmored-hex --yes success", + keyringBackend: keyring.BackendTest, + extraArgs: []string{"--unsafe", "--unarmored-hex", "--yes"}, + userInput: "", + mustFail: false, + expectedOutputContain: "2485e33678db4175dc0ecef2d6e1fc493d4a0d7f7ce83324b6ed70afe77f3485\n", + }, + { + name: "--unsafe --unarmored-hex success", + keyringBackend: keyring.BackendTest, + extraArgs: []string{"--unsafe", "--unarmored-hex"}, + userInput: "y\n", + mustFail: false, + expectedOutputContain: "2485e33678db4175dc0ecef2d6e1fc493d4a0d7f7ce83324b6ed70afe77f3485\n", }, { name: "file keyring backend properly read password and user confirmation", @@ -106,7 +115,11 @@ func Test_runExportCmd(t *testing.T) { require.Error(t, err) } else { require.NoError(t, err) - require.Equal(t, tc.expectedOutput, mockOut.String()) + if tc.expectedOutput != "" { + require.Equal(t, tc.expectedOutput, mockOut.String()) + } else if tc.expectedOutputContain != "" { + require.Contains(t, mockOut.String(), tc.expectedOutputContain) + } } }) } diff --git a/client/keys/mnemonic.go b/client/keys/mnemonic.go index ea7f9638d9..58e1ee9715 100644 --- a/client/keys/mnemonic.go +++ b/client/keys/mnemonic.go @@ -39,13 +39,15 @@ func MnemonicKeyCommand() *cobra.Command { 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 skip, _ := cmd.Flags().GetBool(flagYes); !skip { + yes, err := input.GetConfirmation(fmt.Sprintf("> Input length: %d", len(inputEntropy)), buf, cmd.ErrOrStderr()) + if err != nil { + return err + } - if !conf { - return nil + if !yes { + return nil + } } // hash input entropy to get entropy seed @@ -71,5 +73,6 @@ func MnemonicKeyCommand() *cobra.Command { } cmd.Flags().Bool(flagUserEntropy, false, "Prompt the user to supply their own entropy, instead of relying on the system") + cmd.Flags().BoolP(flagYes, "y", false, "Skip confirmation prompt when check input entropy length") return cmd } diff --git a/client/keys/mnemonic_test.go b/client/keys/mnemonic_test.go index c986e6230b..f2318f6957 100644 --- a/client/keys/mnemonic_test.go +++ b/client/keys/mnemonic_test.go @@ -21,7 +21,7 @@ func Test_RunMnemonicCmdUser(t *testing.T) { cmd := MnemonicKeyCommand() _ = testutil.ApplyMockIODiscardOutErr(cmd) - cmd.SetArgs([]string{fmt.Sprintf("--%s=1", flagUserEntropy)}) + cmd.SetArgs([]string{fmt.Sprintf("--%s", flagUserEntropy)}) err := cmd.Execute() require.Error(t, err) require.Equal(t, "EOF", err.Error()) @@ -35,11 +35,14 @@ func Test_RunMnemonicCmdUser(t *testing.T) { "256-bits is 43 characters in Base-64, and 100 in Base-6. You entered 3, and probably want more", err.Error()) + mockIn, mockOut := testutil.ApplyMockIO(cmd) // Now provide "good" entropy :) fakeEntropy := strings.Repeat(":)", 40) + "\ny\n" // entropy + accept count mockIn.Reset(fakeEntropy) require.NoError(t, cmd.Execute()) + require.Equal(t, "volcano hungry midnight divorce post ship bicycle fitness hospital critic protect ring trim alien there safe fine subway style impulse identify right improve print\n", mockOut.String()) + mockIn = testutil.ApplyMockIODiscardOutErr(cmd) // Now provide "good" entropy but no answer fakeEntropy = strings.Repeat(":)", 40) + "\n" // entropy + accept count mockIn.Reset(fakeEntropy) @@ -49,4 +52,11 @@ func Test_RunMnemonicCmdUser(t *testing.T) { fakeEntropy = strings.Repeat(":)", 40) + "\nn\n" // entropy + accept count mockIn.Reset(fakeEntropy) require.NoError(t, cmd.Execute()) + + // test for skip confirmation + cmd.SetArgs([]string{fmt.Sprintf("--%s", flagUserEntropy), fmt.Sprintf("--%s", flagYes)}) + fakeEntropy = strings.Repeat(":)", 40) + "\n" // entropy + accept count + mockIn.Reset(fakeEntropy) + require.NoError(t, cmd.Execute()) + require.Equal(t, "volcano hungry midnight divorce post ship bicycle fitness hospital critic protect ring trim alien there safe fine subway style impulse identify right improve print\n", mockOut.String()) }