From 043f8f42e5f62679d80e9b081a5b58e99638cdeb Mon Sep 17 00:00:00 2001 From: Halimao <1065621723@qq.com> Date: Tue, 12 Dec 2023 22:44:48 +0800 Subject: [PATCH] feat(client/keys): support display discreetly for keys export (#18684) --- CHANGELOG.md | 1 + client/keys/export.go | 21 +++++++++++++-------- client/keys/export_test.go | 33 +++++++++++++++++++++++---------- 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b7495a0f55e..2931c51fdf0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,6 +59,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (x/staking) [#18636](https://github.com/cosmos/cosmos-sdk/pull/18636) `IterateBondedValidatorsByPower`, `GetDelegatorBonded`, `Delegate`, `Unbond`, `Slash`, `Jail`, `SlashRedelegation`, `ApplyAndReturnValidatorSetUpdates` methods no longer panics on any kind of errors but instead returns appropriate errors. * Usage of `Must...` kind of functions are avoided in keeper methods. * (client/keys) [#18687](https://github.com/cosmos/cosmos-sdk/pull/18687) Improve ` keys mnemonic` by displaying mnemonic discreetly on an alternate screen and adding `--indiscreet` option to disable it. +* (client/keys) [#18684](https://github.com/cosmos/cosmos-sdk/pull/18684) Improve ` keys export` by displaying unarmored hex private key discreetly on an alternate screen and adding `--indiscreet` option to disable it. * (client/keys) [#18663](https://github.com/cosmos/cosmos-sdk/pull/18663) Improve ` keys add` by displaying mnemonic discreetly on an alternate screen and adding `--indiscreet` option to disable it. * (types) [#18440](https://github.com/cosmos/cosmos-sdk/pull/18440) Add `AmountOfNoValidation` to `sdk.DecCoins`. * (client) [#17503](https://github.com/cosmos/cosmos-sdk/pull/17503) Add `client.Context{}.WithAddressCodec`, `WithValidatorAddressCodec`, `WithConsensusAddressCodec` to provide address codecs to the client context. See the [UPGRADING.md](./UPGRADING.md) for more details. diff --git a/client/keys/export.go b/client/keys/export.go index 7e2f7250d38f..0afe6db84133 100644 --- a/client/keys/export.go +++ b/client/keys/export.go @@ -9,7 +9,6 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/input" - "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/crypto/types" ) @@ -42,7 +41,7 @@ and export your keys in ASCII-armored encrypted format.`, unsafe, _ := cmd.Flags().GetBool(flagUnsafe) if unarmored && unsafe { - return exportUnsafeUnarmored(cmd, args[0], buf, clientCtx.Keyring) + return exportUnsafeUnarmored(clientCtx, cmd, args[0], buf) } else if unarmored || unsafe { return fmt.Errorf("the flags %s and %s must be used together", flagUnsafe, flagUnarmoredHex) } @@ -65,25 +64,31 @@ 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().Bool(flagIndiscreet, false, "Print unarmored hex privkey directly on current terminal (only valid when --unarmored-hex is true)") return cmd } -func exportUnsafeUnarmored(cmd *cobra.Command, uid string, buf *bufio.Reader, kr keyring.Keyring) error { - // confirm deletion, unless -y is passed +func exportUnsafeUnarmored(ctx client.Context, cmd *cobra.Command, uid string, buf *bufio.Reader) error { 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) + hexPrivKey, err := unsafeExportPrivKeyHex(ctx.Keyring.(unsafeExporter), uid) if err != nil { return err } - - cmd.Println(hexPrivKey) - + indiscreet, _ := cmd.Flags().GetBool(flagIndiscreet) + if indiscreet { + cmd.Println(hexPrivKey) + return nil + } + if err = printDiscreetly(ctx, cmd.ErrOrStderr(), "**Important** Do not share this private key.", hexPrivKey); err != nil { + return fmt.Errorf("failed to print private key: %w", err) + } + cmd.Println("Export private key successfully") return nil } diff --git a/client/keys/export_test.go b/client/keys/export_test.go index 96d1048e90b5..81036feafeae 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 // only valid when expectedOutput is empty }{ { name: "--unsafe only must fail", @@ -49,9 +50,17 @@ func Test_runExportCmd(t *testing.T) { expectedOutput: "", }, { - name: "--unsafe --unarmored-hex succeed", + name: "--unsafe --unarmored-hex success", + keyringBackend: keyring.BackendTest, + extraArgs: []string{"--unsafe", "--unarmored-hex"}, + userInput: "y\n", + mustFail: false, + expectedOutputContain: "2485e33678db4175dc0ecef2d6e1fc493d4a0d7f7ce83324b6ed70afe77f3485\n", + }, + { + name: "--unsafe --unarmored-hex --indiscreet success", keyringBackend: keyring.BackendTest, - extraArgs: []string{"--unsafe", "--unarmored-hex"}, + extraArgs: []string{"--unsafe", "--unarmored-hex", "--indiscreet"}, userInput: "y\n", mustFail: false, expectedOutput: "2485e33678db4175dc0ecef2d6e1fc493d4a0d7f7ce83324b6ed70afe77f3485\n", @@ -59,7 +68,7 @@ func Test_runExportCmd(t *testing.T) { { name: "file keyring backend properly read password and user confirmation", keyringBackend: keyring.BackendFile, - extraArgs: []string{"--unsafe", "--unarmored-hex"}, + extraArgs: []string{"--unsafe", "--unarmored-hex", "--indiscreet"}, // first 2 pass for creating the key, then unsafe export confirmation, then unlock keyring pass userInput: "12345678\n12345678\ny\n12345678\n", mustFail: false, @@ -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) + } } }) }