feat(client/keys): support display discreetly for keys export (#18684)

This commit is contained in:
Halimao 2023-12-12 22:44:48 +08:00 committed by GitHub
parent f84a123151
commit 043f8f42e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 37 additions and 18 deletions

View File

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

View File

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

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