feat(client/keys): add --yes option to keys export and keys mnemonic (backport #18745) (#24154)

Co-authored-by: levisyin <150114626+levisyin@users.noreply.github.com>
Co-authored-by: aljo242 <alex@interchainlabs.io>
This commit is contained in:
mergify[bot] 2025-03-27 03:10:13 +00:00 committed by GitHub
parent 0f52ccd54a
commit fc725a35d6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 55 additions and 26 deletions

View File

@ -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 `<appd> keys export` and `<appd> 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.

View File

@ -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)

View File

@ -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)
}
}
})
}

View File

@ -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
}

View File

@ -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())
}