Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 9 commits into from
Dec 12, 2023
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

### Improvements

* (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.
* (telemetry) [#18646] (https://github.com/cosmos/cosmos-sdk/pull/18646) Enable statsd and dogstatsd telemetry sinks
* (types) [#18440](https://github.com/cosmos/cosmos-sdk/pull/18440) Add `AmountOfNoValidation` to `sdk.DecCoins`.
Expand Down
19 changes: 13 additions & 6 deletions client/keys/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -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)
}
Expand All @@ -65,24 +64,32 @@ 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)")
Halimao marked this conversation as resolved.
Show resolved Hide resolved

return cmd
}

func exportUnsafeUnarmored(cmd *cobra.Command, uid string, buf *bufio.Reader, kr keyring.Keyring) error {
func exportUnsafeUnarmored(ctx client.Context, cmd *cobra.Command, uid string, buf *bufio.Reader) error {
// confirm deletion, unless -y is passed
Halimao marked this conversation as resolved.
Show resolved Hide resolved
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)
Halimao marked this conversation as resolved.
Show resolved Hide resolved
} else {
if err = printDiscreetly(ctx, cmd.ErrOrStderr(), "**Important** Do not share this private key.", hexPrivKey); err != nil {
Halimao marked this conversation as resolved.
Show resolved Hide resolved
return fmt.Errorf("failed to print private key: %w", err)
}
cmd.Println("Export private key successfully")
}

return nil
}
Expand Down
33 changes: 23 additions & 10 deletions client/keys/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -49,17 +50,25 @@ 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",
},
{
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,
Expand Down Expand Up @@ -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)
}
}
})
}
Expand Down
Loading