Interchangable PrivKey implementations in keybase (#5278)
Allow for the keybase to be configured to override the implementation of the key that is saved to the keybase. Closes: #4941
This commit is contained in:
committed by
Alessio Treglia
parent
efcd5fd315
commit
0e28da23e7
+25
-16
@@ -5,6 +5,7 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
|
||||
bip39 "github.com/bartekn/go-bip39"
|
||||
@@ -36,7 +37,8 @@ const (
|
||||
DefaultKeyPass = "12345678"
|
||||
)
|
||||
|
||||
func addKeyCommand() *cobra.Command {
|
||||
// AddKeyCommand defines a keys command to add a generated or recovered private key to keybase.
|
||||
func AddKeyCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "add <name>",
|
||||
Short: "Add an encrypted private key (either newly generated or recovered), encrypt it, and save to disk",
|
||||
@@ -75,6 +77,24 @@ the flag --nosort is set.
|
||||
return cmd
|
||||
}
|
||||
|
||||
func getKeybase(transient bool, buf io.Reader) (keys.Keybase, error) {
|
||||
if transient {
|
||||
return keys.NewInMemory(), nil
|
||||
}
|
||||
|
||||
return NewKeyringFromHomeFlag(buf)
|
||||
}
|
||||
|
||||
func runAddCmd(cmd *cobra.Command, args []string) error {
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
kb, err := getKeybase(viper.GetBool(flagDryRun), inBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return RunAddCmd(cmd, args, kb, inBuf)
|
||||
}
|
||||
|
||||
/*
|
||||
input
|
||||
- bip39 mnemonic
|
||||
@@ -84,26 +104,15 @@ input
|
||||
output
|
||||
- armor encrypted private key (saved to file)
|
||||
*/
|
||||
func runAddCmd(cmd *cobra.Command, args []string) error {
|
||||
var kb keys.Keybase
|
||||
func RunAddCmd(cmd *cobra.Command, args []string, kb keys.Keybase, inBuf *bufio.Reader) error {
|
||||
var err error
|
||||
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
name := args[0]
|
||||
|
||||
interactive := viper.GetBool(flagInteractive)
|
||||
showMnemonic := !viper.GetBool(flagNoBackup)
|
||||
|
||||
if viper.GetBool(flagDryRun) {
|
||||
// we throw this away, so don't enforce args,
|
||||
// we want to get a new random seed phrase quickly
|
||||
kb = keys.NewInMemory()
|
||||
} else {
|
||||
kb, err = NewKeyringFromHomeFlag(cmd.InOrStdin())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !viper.GetBool(flagDryRun) {
|
||||
_, err = kb.Get(name)
|
||||
if err == nil {
|
||||
// account exists, ask for user confirmation
|
||||
@@ -273,9 +282,9 @@ func printCreate(cmd *cobra.Command, info keys.Info, showMnemonic bool, mnemonic
|
||||
|
||||
var jsonString []byte
|
||||
if viper.GetBool(flags.FlagIndentResponse) {
|
||||
jsonString, err = cdc.MarshalJSONIndent(out, "", " ")
|
||||
jsonString, err = KeysCdc.MarshalJSONIndent(out, "", " ")
|
||||
} else {
|
||||
jsonString, err = cdc.MarshalJSON(out)
|
||||
jsonString, err = KeysCdc.MarshalJSON(out)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -33,7 +33,7 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) {
|
||||
config.SetBech32PrefixForValidator(bech32PrefixValAddr, bech32PrefixValPub)
|
||||
config.SetBech32PrefixForConsensusNode(bech32PrefixConsAddr, bech32PrefixConsPub)
|
||||
|
||||
cmd := addKeyCommand()
|
||||
cmd := AddKeyCommand()
|
||||
require.NotNil(t, cmd)
|
||||
|
||||
// Prepare a keybase
|
||||
@@ -80,7 +80,7 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) {
|
||||
|
||||
func Test_runAddCmdLedger(t *testing.T) {
|
||||
runningUnattended := isRunningUnattended()
|
||||
cmd := addKeyCommand()
|
||||
cmd := AddKeyCommand()
|
||||
require.NotNil(t, cmd)
|
||||
mockIn, _, _ := tests.ApplyMockIO(cmd)
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
|
||||
func Test_runAddCmdBasic(t *testing.T) {
|
||||
runningUnattended := isRunningUnattended()
|
||||
cmd := addKeyCommand()
|
||||
cmd := AddKeyCommand()
|
||||
assert.NotNil(t, cmd)
|
||||
mockIn, _, _ := tests.ApplyMockIO(cmd)
|
||||
|
||||
|
||||
@@ -4,20 +4,21 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
)
|
||||
|
||||
var cdc *codec.Codec
|
||||
// KeysCdc defines codec to be used with key operations
|
||||
var KeysCdc *codec.Codec
|
||||
|
||||
func init() {
|
||||
cdc = codec.New()
|
||||
codec.RegisterCrypto(cdc)
|
||||
cdc.Seal()
|
||||
KeysCdc = codec.New()
|
||||
codec.RegisterCrypto(KeysCdc)
|
||||
KeysCdc.Seal()
|
||||
}
|
||||
|
||||
// marshal keys
|
||||
func MarshalJSON(o interface{}) ([]byte, error) {
|
||||
return cdc.MarshalJSON(o)
|
||||
return KeysCdc.MarshalJSON(o)
|
||||
}
|
||||
|
||||
// unmarshal json
|
||||
func UnmarshalJSON(bz []byte, ptr interface{}) error {
|
||||
return cdc.UnmarshalJSON(bz, ptr)
|
||||
return KeysCdc.UnmarshalJSON(bz, ptr)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@ const (
|
||||
flagForce = "force"
|
||||
)
|
||||
|
||||
func deleteKeyCommand() *cobra.Command {
|
||||
// DeleteKeyCommand deletes a key from the key store.
|
||||
func DeleteKeyCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "delete <name>...",
|
||||
Short: "Delete the given keys",
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
|
||||
func Test_runDeleteCmd(t *testing.T) {
|
||||
runningUnattended := isRunningUnattended()
|
||||
deleteKeyCommand := deleteKeyCommand()
|
||||
deleteKeyCommand := DeleteKeyCommand()
|
||||
mockIn, _, _ := tests.ApplyMockIO(deleteKeyCommand)
|
||||
|
||||
yesF, _ := deleteKeyCommand.Flags().GetBool(flagYes)
|
||||
|
||||
@@ -8,7 +8,8 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/client/input"
|
||||
)
|
||||
|
||||
func exportKeyCommand() *cobra.Command {
|
||||
// ExportKeyCommand exports private keys from the key store.
|
||||
func ExportKeyCommand() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "export <name>",
|
||||
Short: "Export private keys",
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
func Test_runExportCmd(t *testing.T) {
|
||||
runningUnattended := isRunningUnattended()
|
||||
exportKeyCommand := exportKeyCommand()
|
||||
exportKeyCommand := ExportKeyCommand()
|
||||
mockIn, _, _ := tests.ApplyMockIO(exportKeyCommand)
|
||||
|
||||
// Now add a temporary keybase
|
||||
|
||||
@@ -9,7 +9,8 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/client/input"
|
||||
)
|
||||
|
||||
func importKeyCommand() *cobra.Command {
|
||||
// ImportKeyCommand imports private keys from a keyfile.
|
||||
func ImportKeyCommand() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "import <name> <keyfile>",
|
||||
Short: "Import private keys into the local keybase",
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
|
||||
func Test_runImportCmd(t *testing.T) {
|
||||
runningUnattended := isRunningUnattended()
|
||||
importKeyCommand := importKeyCommand()
|
||||
importKeyCommand := ImportKeyCommand()
|
||||
mockIn, _, _ := tests.ApplyMockIO(importKeyCommand)
|
||||
|
||||
// Now add a temporary keybase
|
||||
|
||||
+2
-1
@@ -9,7 +9,8 @@ import (
|
||||
|
||||
const flagListNames = "list-names"
|
||||
|
||||
func listKeysCmd() *cobra.Command {
|
||||
// ListKeysCmd lists all keys in the key store.
|
||||
func ListKeysCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List all keys",
|
||||
|
||||
@@ -18,7 +18,7 @@ func Test_runListCmd(t *testing.T) {
|
||||
args []string
|
||||
}
|
||||
|
||||
cmdBasic := listKeysCmd()
|
||||
cmdBasic := ListKeysCmd()
|
||||
|
||||
// Prepare some keybases
|
||||
kbHome1, cleanUp1 := tests.NewTestCaseDir(t)
|
||||
|
||||
@@ -18,7 +18,8 @@ import (
|
||||
// is not needed for importing into the Keyring keystore.
|
||||
const migratePassphrase = "NOOP_PASSPHRASE"
|
||||
|
||||
func migrateCommand() *cobra.Command {
|
||||
// MigrateCommand migrates key information from legacy keybase to OS secret store.
|
||||
func MigrateCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "migrate",
|
||||
Short: "Migrate key information from the lagacy key database to the OS secret store, or encrypted file store as a fall-back and save it",
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_runMigrateCmd(t *testing.T) {
|
||||
cmd := addKeyCommand()
|
||||
cmd := AddKeyCommand()
|
||||
assert.NotNil(t, cmd)
|
||||
mockIn, _, _ := tests.ApplyMockIO(cmd)
|
||||
|
||||
@@ -29,7 +29,7 @@ func Test_runMigrateCmd(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
|
||||
viper.Set(flags.FlagDryRun, true)
|
||||
cmd = migrateCommand()
|
||||
cmd = MigrateCommand()
|
||||
mockIn, _, _ = tests.ApplyMockIO(cmd)
|
||||
mockIn.Reset("test1234\n")
|
||||
assert.NoError(t, runMigrateCmd(cmd, []string{}))
|
||||
|
||||
@@ -17,7 +17,8 @@ const (
|
||||
mnemonicEntropySize = 256
|
||||
)
|
||||
|
||||
func mnemonicKeyCommand() *cobra.Command {
|
||||
// MnemonicKeyCommand computes the bip39 memonic for input entropy.
|
||||
func MnemonicKeyCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "mnemonic",
|
||||
Short: "Compute the bip39 mnemonic for some input entropy",
|
||||
|
||||
@@ -11,13 +11,13 @@ import (
|
||||
)
|
||||
|
||||
func Test_RunMnemonicCmdNormal(t *testing.T) {
|
||||
cmdBasic := mnemonicKeyCommand()
|
||||
cmdBasic := MnemonicKeyCommand()
|
||||
err := runMnemonicCmd(cmdBasic, []string{})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func Test_RunMnemonicCmdUser(t *testing.T) {
|
||||
cmdUser := mnemonicKeyCommand()
|
||||
cmdUser := MnemonicKeyCommand()
|
||||
err := cmdUser.Flags().Set(flagUserEntropy, "1")
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
||||
@@ -67,7 +67,8 @@ func (bo bech32Output) String() string {
|
||||
return fmt.Sprintf("Bech32 Formats:\n%s", strings.Join(out, "\n"))
|
||||
}
|
||||
|
||||
func parseKeyStringCommand() *cobra.Command {
|
||||
// ParseKeyStringCommand parses an address from hex to bech32 and vice versa.
|
||||
func ParseKeyStringCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "parse <hex-or-bech32-address>",
|
||||
Short: "Parse address from hex to bech32 and vice versa",
|
||||
@@ -124,9 +125,9 @@ func displayParseKeyInfo(stringer fmt.Stringer) {
|
||||
case OutputFormatJSON:
|
||||
|
||||
if viper.GetBool(flags.FlagIndentResponse) {
|
||||
out, err = cdc.MarshalJSONIndent(stringer, "", " ")
|
||||
out, err = KeysCdc.MarshalJSONIndent(stringer, "", " ")
|
||||
} else {
|
||||
out = cdc.MustMarshalJSON(stringer)
|
||||
out = KeysCdc.MustMarshalJSON(stringer)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+10
-10
@@ -20,17 +20,17 @@ func Commands() *cobra.Command {
|
||||
needs to sign with a private key.`,
|
||||
}
|
||||
cmd.AddCommand(
|
||||
mnemonicKeyCommand(),
|
||||
addKeyCommand(),
|
||||
exportKeyCommand(),
|
||||
importKeyCommand(),
|
||||
listKeysCmd(),
|
||||
showKeysCmd(),
|
||||
MnemonicKeyCommand(),
|
||||
AddKeyCommand(),
|
||||
ExportKeyCommand(),
|
||||
ImportKeyCommand(),
|
||||
ListKeysCmd(),
|
||||
ShowKeysCmd(),
|
||||
flags.LineBreak,
|
||||
deleteKeyCommand(),
|
||||
updateKeyCommand(),
|
||||
parseKeyStringCommand(),
|
||||
migrateCommand(),
|
||||
DeleteKeyCommand(),
|
||||
UpdateKeyCommand(),
|
||||
ParseKeyStringCommand(),
|
||||
MigrateCommand(),
|
||||
)
|
||||
cmd.PersistentFlags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|test)")
|
||||
viper.BindPFlag(flags.FlagKeyringBackend, cmd.Flags().Lookup(flags.FlagKeyringBackend))
|
||||
|
||||
+2
-1
@@ -32,7 +32,8 @@ const (
|
||||
defaultMultiSigKeyName = "multi"
|
||||
)
|
||||
|
||||
func showKeysCmd() *cobra.Command {
|
||||
// ShowKeysCmd shows key information for a given key name.
|
||||
func ShowKeysCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "show [name [name...]]",
|
||||
Short: "Show key info for the given name",
|
||||
|
||||
@@ -28,7 +28,7 @@ func Test_multiSigKey_Properties(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_showKeysCmd(t *testing.T) {
|
||||
cmd := showKeysCmd()
|
||||
cmd := ShowKeysCmd()
|
||||
require.NotNil(t, cmd)
|
||||
require.Equal(t, "false", cmd.Flag(FlagAddress).DefValue)
|
||||
require.Equal(t, "false", cmd.Flag(FlagPublicKey).DefValue)
|
||||
@@ -36,7 +36,7 @@ func Test_showKeysCmd(t *testing.T) {
|
||||
|
||||
func Test_runShowCmd(t *testing.T) {
|
||||
runningUnattended := isRunningUnattended()
|
||||
cmd := showKeysCmd()
|
||||
cmd := ShowKeysCmd()
|
||||
mockIn, _, _ := tests.ApplyMockIO(cmd)
|
||||
require.EqualError(t, runShowCmd(cmd, []string{"invalid"}), "The specified item could not be found in the keyring")
|
||||
require.EqualError(t, runShowCmd(cmd, []string{"invalid1", "invalid2"}), "The specified item could not be found in the keyring")
|
||||
|
||||
@@ -8,7 +8,9 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/client/input"
|
||||
)
|
||||
|
||||
func updateKeyCommand() *cobra.Command {
|
||||
// UpdateKeyCommand changes the password of a key in the keybase.
|
||||
// It takes no effect on keys managed by new the keyring-based keybase implementation.
|
||||
func UpdateKeyCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "update <name>",
|
||||
Short: "Change the password used to protect private key",
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_updateKeyCommand(t *testing.T) {
|
||||
cmd := updateKeyCommand()
|
||||
cmd := UpdateKeyCommand()
|
||||
assert.NotNil(t, cmd)
|
||||
// No flags or defaults to validate
|
||||
}
|
||||
@@ -20,7 +20,7 @@ func Test_runUpdateCmd(t *testing.T) {
|
||||
fakeKeyName1 := "runUpdateCmd_Key1"
|
||||
fakeKeyName2 := "runUpdateCmd_Key2"
|
||||
|
||||
cmd := updateKeyCommand()
|
||||
cmd := UpdateKeyCommand()
|
||||
|
||||
// fails because it requests a password
|
||||
assert.EqualError(t, runUpdateCmd(cmd, []string{fakeKeyName1}), "EOF")
|
||||
|
||||
+19
-16
@@ -26,30 +26,33 @@ const (
|
||||
|
||||
type bechKeyOutFn func(keyInfo keys.Info) (keys.KeyOutput, error)
|
||||
|
||||
// NewKeyBaseFromHomeFlag initializes a Keybase based on the configuration.
|
||||
func NewKeyBaseFromHomeFlag() (keys.Keybase, error) {
|
||||
// NewKeyBaseFromHomeFlag initializes a Keybase based on the configuration. Keybase
|
||||
// options can be applied when generating this new Keybase.
|
||||
func NewKeyBaseFromHomeFlag(opts ...keys.KeybaseOption) (keys.Keybase, error) {
|
||||
rootDir := viper.GetString(flags.FlagHome)
|
||||
return NewKeyBaseFromDir(rootDir)
|
||||
return NewKeyBaseFromDir(rootDir, opts...)
|
||||
}
|
||||
|
||||
// NewKeyBaseFromDir initializes a keybase at a particular dir.
|
||||
func NewKeyBaseFromDir(rootDir string) (keys.Keybase, error) {
|
||||
return getLazyKeyBaseFromDir(rootDir)
|
||||
// NewKeyBaseFromDir initializes a keybase at the rootDir directory. Keybase
|
||||
// options can be applied when generating this new Keybase.
|
||||
func NewKeyBaseFromDir(rootDir string, opts ...keys.KeybaseOption) (keys.Keybase, error) {
|
||||
return getLazyKeyBaseFromDir(rootDir, opts...)
|
||||
}
|
||||
|
||||
// NewInMemoryKeyBase returns a storage-less keybase.
|
||||
func NewInMemoryKeyBase() keys.Keybase { return keys.NewInMemory() }
|
||||
|
||||
// NewKeyBaseFromHomeFlag initializes a keyring based on configuration.
|
||||
func NewKeyringFromHomeFlag(input io.Reader) (keys.Keybase, error) {
|
||||
return NewKeyringFromDir(viper.GetString(flags.FlagHome), input)
|
||||
// NewKeyBaseFromHomeFlag initializes a keyring based on configuration. Keybase
|
||||
// options can be applied when generating this new Keybase.
|
||||
func NewKeyringFromHomeFlag(input io.Reader, opts ...keys.KeybaseOption) (keys.Keybase, error) {
|
||||
return NewKeyringFromDir(viper.GetString(flags.FlagHome), input, opts...)
|
||||
}
|
||||
|
||||
// NewKeyBaseFromDir initializes a keyring at the given directory.
|
||||
// If the viper flag flags.FlagKeyringBackend is set to file, it returns an on-disk keyring with
|
||||
// CLI prompt support only. If flags.FlagKeyringBackend is set to test it will return an on-disk,
|
||||
// password-less keyring that could be used for testing purposes.
|
||||
func NewKeyringFromDir(rootDir string, input io.Reader) (keys.Keybase, error) {
|
||||
func NewKeyringFromDir(rootDir string, input io.Reader, opts ...keys.KeybaseOption) (keys.Keybase, error) {
|
||||
keyringBackend := viper.GetString(flags.FlagKeyringBackend)
|
||||
switch keyringBackend {
|
||||
case flags.KeyringBackendTest:
|
||||
@@ -62,8 +65,8 @@ func NewKeyringFromDir(rootDir string, input io.Reader) (keys.Keybase, error) {
|
||||
return nil, fmt.Errorf("unknown keyring backend %q", keyringBackend)
|
||||
}
|
||||
|
||||
func getLazyKeyBaseFromDir(rootDir string) (keys.Keybase, error) {
|
||||
return keys.New(defaultKeyDBName, filepath.Join(rootDir, "keys")), nil
|
||||
func getLazyKeyBaseFromDir(rootDir string, opts ...keys.KeybaseOption) (keys.Keybase, error) {
|
||||
return keys.New(defaultKeyDBName, filepath.Join(rootDir, "keys"), opts...), nil
|
||||
}
|
||||
|
||||
func printKeyInfo(keyInfo keys.Info, bechKeyOut bechKeyOutFn) {
|
||||
@@ -80,9 +83,9 @@ func printKeyInfo(keyInfo keys.Info, bechKeyOut bechKeyOutFn) {
|
||||
var out []byte
|
||||
var err error
|
||||
if viper.GetBool(flags.FlagIndentResponse) {
|
||||
out, err = cdc.MarshalJSONIndent(ko, "", " ")
|
||||
out, err = KeysCdc.MarshalJSONIndent(ko, "", " ")
|
||||
} else {
|
||||
out, err = cdc.MarshalJSON(ko)
|
||||
out, err = KeysCdc.MarshalJSON(ko)
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -107,9 +110,9 @@ func printInfos(infos []keys.Info) {
|
||||
var err error
|
||||
|
||||
if viper.GetBool(flags.FlagIndentResponse) {
|
||||
out, err = cdc.MarshalJSONIndent(kos, "", " ")
|
||||
out, err = KeysCdc.MarshalJSONIndent(kos, "", " ")
|
||||
} else {
|
||||
out, err = cdc.MarshalJSON(kos)
|
||||
out, err = KeysCdc.MarshalJSON(kos)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user