2018-02-22 07:17:19 -08:00
|
|
|
package keys
|
|
|
|
|
|
|
|
import (
|
2019-02-25 03:34:39 -08:00
|
|
|
"errors"
|
2018-08-30 21:06:44 -07:00
|
|
|
"fmt"
|
2019-04-04 07:36:39 -07:00
|
|
|
|
2018-02-22 07:17:19 -08:00
|
|
|
"github.com/spf13/cobra"
|
2018-08-10 23:42:57 -07:00
|
|
|
"github.com/spf13/viper"
|
2019-02-25 03:34:39 -08:00
|
|
|
|
|
|
|
tmcrypto "github.com/tendermint/tendermint/crypto"
|
2018-10-22 11:50:21 -07:00
|
|
|
"github.com/tendermint/tendermint/crypto/multisig"
|
2018-09-24 08:06:38 -07:00
|
|
|
"github.com/tendermint/tendermint/libs/cli"
|
2019-05-28 01:44:04 -07:00
|
|
|
|
|
|
|
"github.com/cosmos/cosmos-sdk/client/flags"
|
|
|
|
"github.com/cosmos/cosmos-sdk/crypto"
|
2020-03-25 08:20:36 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
2019-05-28 01:44:04 -07:00
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
2018-08-10 23:42:57 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// FlagAddress is the flag for the user's address on the command line.
|
|
|
|
FlagAddress = "address"
|
|
|
|
// FlagPublicKey represents the user's public key on the command line.
|
|
|
|
FlagPublicKey = "pubkey"
|
2018-09-12 00:14:29 -07:00
|
|
|
// FlagBechPrefix defines a desired Bech32 prefix encoding for a key.
|
2018-08-30 21:06:44 -07:00
|
|
|
FlagBechPrefix = "bech"
|
2019-04-30 01:58:21 -07:00
|
|
|
// FlagDevice indicates that the information should be shown in the device
|
2019-02-25 03:34:39 -08:00
|
|
|
FlagDevice = "device"
|
2018-10-22 11:50:21 -07:00
|
|
|
|
2019-03-01 13:29:33 -08:00
|
|
|
flagMultiSigThreshold = "multisig-threshold"
|
|
|
|
|
2018-10-23 11:46:43 -07:00
|
|
|
defaultMultiSigKeyName = "multi"
|
2018-02-22 07:17:19 -08:00
|
|
|
)
|
|
|
|
|
2019-12-12 13:52:24 -08:00
|
|
|
// ShowKeysCmd shows key information for a given key name.
|
|
|
|
func ShowKeysCmd() *cobra.Command {
|
2018-08-30 21:06:44 -07:00
|
|
|
cmd := &cobra.Command{
|
2020-03-30 07:54:01 -07:00
|
|
|
Use: "show [name_or_address [name_or_address...]]",
|
|
|
|
Short: "Retrieve key information by name or address",
|
|
|
|
Long: `Display keys details. If multiple names or addresses are provided,
|
|
|
|
then an ephemeral multisig key will be created under the name "multi"
|
2019-03-01 13:29:33 -08:00
|
|
|
consisting of all the keys provided by name and multisig threshold.`,
|
|
|
|
Args: cobra.MinimumNArgs(1),
|
|
|
|
RunE: runShowCmd,
|
2018-08-30 21:06:44 -07:00
|
|
|
}
|
|
|
|
|
2019-02-18 13:35:08 -08:00
|
|
|
cmd.Flags().String(FlagBechPrefix, sdk.PrefixAccount, "The Bech32 prefix encoding for a key (acc|val|cons)")
|
2019-03-01 13:29:33 -08:00
|
|
|
cmd.Flags().BoolP(FlagAddress, "a", false, "Output the address only (overrides --output)")
|
|
|
|
cmd.Flags().BoolP(FlagPublicKey, "p", false, "Output the public key only (overrides --output)")
|
2019-04-30 01:58:21 -07:00
|
|
|
cmd.Flags().BoolP(FlagDevice, "d", false, "Output the address in a ledger device")
|
2018-10-23 11:44:47 -07:00
|
|
|
cmd.Flags().Uint(flagMultiSigThreshold, 1, "K out of N required signatures")
|
2019-05-28 01:44:04 -07:00
|
|
|
cmd.Flags().Bool(flags.FlagIndentResponse, false, "Add indent to JSON response")
|
2018-08-10 23:42:57 -07:00
|
|
|
|
2018-08-30 21:06:44 -07:00
|
|
|
return cmd
|
2018-02-22 07:17:19 -08:00
|
|
|
}
|
|
|
|
|
2018-10-22 11:50:21 -07:00
|
|
|
func runShowCmd(cmd *cobra.Command, args []string) (err error) {
|
2020-03-25 08:20:36 -07:00
|
|
|
var info keyring.Info
|
2018-09-12 00:14:29 -07:00
|
|
|
|
2020-04-08 02:38:28 -07:00
|
|
|
kb, err := keyring.New(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), cmd.InOrStdin())
|
2019-11-14 06:17:21 -08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-10-22 11:50:21 -07:00
|
|
|
if len(args) == 1 {
|
2020-03-30 07:54:01 -07:00
|
|
|
info, err = fetchKey(kb, args[0])
|
2018-10-22 11:50:21 -07:00
|
|
|
if err != nil {
|
2020-03-30 07:54:01 -07:00
|
|
|
return fmt.Errorf("%s is not a valid name or address: %v", args[0], err)
|
2018-10-22 11:50:21 -07:00
|
|
|
}
|
|
|
|
} else {
|
2019-02-25 03:34:39 -08:00
|
|
|
pks := make([]tmcrypto.PubKey, len(args))
|
2020-03-30 07:54:01 -07:00
|
|
|
for i, keyref := range args {
|
|
|
|
info, err := fetchKey(kb, keyref)
|
2018-10-22 11:50:21 -07:00
|
|
|
if err != nil {
|
2020-03-30 07:54:01 -07:00
|
|
|
return fmt.Errorf("%s is not a valid name or address: %v", keyref, err)
|
2018-10-22 11:50:21 -07:00
|
|
|
}
|
2019-03-01 13:29:33 -08:00
|
|
|
|
2018-10-22 11:50:21 -07:00
|
|
|
pks[i] = info.GetPubKey()
|
|
|
|
}
|
2018-10-22 17:13:36 -07:00
|
|
|
|
|
|
|
multisigThreshold := viper.GetInt(flagMultiSigThreshold)
|
|
|
|
err = validateMultisigThreshold(multisigThreshold, len(args))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-03-01 13:29:33 -08:00
|
|
|
|
2018-10-22 17:13:36 -07:00
|
|
|
multikey := multisig.NewPubKeyMultisigThreshold(multisigThreshold, pks)
|
2020-03-25 08:20:36 -07:00
|
|
|
info = keyring.NewMultiInfo(defaultMultiSigKeyName, multikey)
|
2018-09-12 00:14:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
isShowAddr := viper.GetBool(FlagAddress)
|
|
|
|
isShowPubKey := viper.GetBool(FlagPublicKey)
|
2019-02-25 03:34:39 -08:00
|
|
|
isShowDevice := viper.GetBool(FlagDevice)
|
2019-02-08 12:45:23 -08:00
|
|
|
|
|
|
|
isOutputSet := false
|
|
|
|
tmp := cmd.Flag(cli.OutputFlag)
|
|
|
|
if tmp != nil {
|
|
|
|
isOutputSet = tmp.Changed
|
|
|
|
}
|
2018-09-12 00:14:29 -07:00
|
|
|
|
|
|
|
if isShowAddr && isShowPubKey {
|
|
|
|
return errors.New("cannot use both --address and --pubkey at once")
|
|
|
|
}
|
|
|
|
|
|
|
|
if isOutputSet && (isShowAddr || isShowPubKey) {
|
|
|
|
return errors.New("cannot use --output with --address or --pubkey")
|
|
|
|
}
|
|
|
|
|
|
|
|
bechKeyOut, err := getBechKeyOut(viper.GetString(FlagBechPrefix))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
switch {
|
|
|
|
case isShowAddr:
|
2020-03-30 07:54:01 -07:00
|
|
|
printKeyAddress(cmd.OutOrStdout(), info, bechKeyOut)
|
2018-09-12 00:14:29 -07:00
|
|
|
case isShowPubKey:
|
2020-03-30 07:54:01 -07:00
|
|
|
printPubKey(cmd.OutOrStdout(), info, bechKeyOut)
|
2018-09-12 00:14:29 -07:00
|
|
|
default:
|
2020-03-30 07:54:01 -07:00
|
|
|
printKeyInfo(cmd.OutOrStdout(), info, bechKeyOut)
|
2018-09-12 00:14:29 -07:00
|
|
|
}
|
|
|
|
|
2019-02-25 03:34:39 -08:00
|
|
|
if isShowDevice {
|
|
|
|
if isShowPubKey {
|
|
|
|
return fmt.Errorf("the device flag (-d) can only be used for addresses not pubkeys")
|
|
|
|
}
|
|
|
|
if viper.GetString(FlagBechPrefix) != "acc" {
|
|
|
|
return fmt.Errorf("the device flag (-d) can only be used for accounts")
|
|
|
|
}
|
|
|
|
// Override and show in the device
|
2020-03-25 08:20:36 -07:00
|
|
|
if info.GetType() != keyring.TypeLedger {
|
2019-02-25 03:34:39 -08:00
|
|
|
return fmt.Errorf("the device flag (-d) can only be used for accounts stored in devices")
|
|
|
|
}
|
|
|
|
|
|
|
|
hdpath, err := info.GetPath()
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-03-01 09:16:22 -08:00
|
|
|
return crypto.LedgerShowAddress(*hdpath, info.GetPubKey(), sdk.GetConfig().GetBech32AccountAddrPrefix())
|
2019-02-25 03:34:39 -08:00
|
|
|
}
|
|
|
|
|
2018-09-12 00:14:29 -07:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-04-08 02:38:28 -07:00
|
|
|
func fetchKey(kb keyring.Keyring, keyref string) (keyring.Info, error) {
|
|
|
|
info, err := kb.Key(keyref)
|
2020-03-30 07:54:01 -07:00
|
|
|
if err != nil {
|
|
|
|
accAddr, err := sdk.AccAddressFromBech32(keyref)
|
|
|
|
if err != nil {
|
|
|
|
return info, err
|
|
|
|
}
|
|
|
|
|
2020-04-08 02:38:28 -07:00
|
|
|
info, err = kb.KeyByAddress(accAddr)
|
2020-03-30 07:54:01 -07:00
|
|
|
if err != nil {
|
|
|
|
return info, errors.New("key not found")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return info, nil
|
|
|
|
}
|
|
|
|
|
2018-10-22 17:13:36 -07:00
|
|
|
func validateMultisigThreshold(k, nKeys int) error {
|
|
|
|
if k <= 0 {
|
|
|
|
return fmt.Errorf("threshold must be a positive integer")
|
|
|
|
}
|
|
|
|
if nKeys < k {
|
|
|
|
return fmt.Errorf(
|
|
|
|
"threshold k of n multisignature: %d < %d", nKeys, k)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-08-30 21:06:44 -07:00
|
|
|
func getBechKeyOut(bechPrefix string) (bechKeyOutFn, error) {
|
|
|
|
switch bechPrefix {
|
2019-02-18 13:35:08 -08:00
|
|
|
case sdk.PrefixAccount:
|
2020-03-25 08:20:36 -07:00
|
|
|
return keyring.Bech32KeyOutput, nil
|
2019-02-18 13:35:08 -08:00
|
|
|
case sdk.PrefixValidator:
|
2020-03-25 08:20:36 -07:00
|
|
|
return keyring.Bech32ValKeyOutput, nil
|
2019-02-18 13:35:08 -08:00
|
|
|
case sdk.PrefixConsensus:
|
2020-03-25 08:20:36 -07:00
|
|
|
return keyring.Bech32ConsKeyOutput, nil
|
2018-08-30 21:06:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil, fmt.Errorf("invalid Bech32 prefix encoding provided: %s", bechPrefix)
|
2018-08-10 23:42:57 -07:00
|
|
|
}
|