github.com/Finschia/finschia-sdk@v0.48.1/client/keys/parse.go (about)

     1  package keys
     2  
     3  import (
     4  	"encoding/hex"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"strings"
     9  
    10  	"github.com/Finschia/ostracon/libs/cli"
    11  	"github.com/spf13/cobra"
    12  	yaml "gopkg.in/yaml.v2"
    13  
    14  	sdk "github.com/Finschia/finschia-sdk/types"
    15  	"github.com/Finschia/finschia-sdk/types/bech32"
    16  )
    17  
    18  func bech32Prefixes(config *sdk.Config) []string {
    19  	return []string{
    20  		config.GetBech32AccountAddrPrefix(),
    21  		config.GetBech32AccountPubPrefix(),
    22  		config.GetBech32ValidatorAddrPrefix(),
    23  		config.GetBech32ValidatorPubPrefix(),
    24  		config.GetBech32ConsensusAddrPrefix(),
    25  		config.GetBech32ConsensusPubPrefix(),
    26  	}
    27  }
    28  
    29  type hexOutput struct {
    30  	Human string `json:"human"`
    31  	Bytes string `json:"bytes"`
    32  }
    33  
    34  func (ho hexOutput) String() string {
    35  	return fmt.Sprintf("Human readable part: %v\nBytes (hex): %s", ho.Human, ho.Bytes)
    36  }
    37  
    38  func newHexOutput(human string, bs []byte) hexOutput {
    39  	return hexOutput{Human: human, Bytes: fmt.Sprintf("%X", bs)}
    40  }
    41  
    42  type bech32Output struct {
    43  	Formats []string `json:"formats"`
    44  }
    45  
    46  func newBech32Output(config *sdk.Config, bs []byte) bech32Output {
    47  	bech32Prefixes := bech32Prefixes(config)
    48  	out := bech32Output{Formats: make([]string, len(bech32Prefixes))}
    49  
    50  	for i, prefix := range bech32Prefixes {
    51  		bech32Addr, err := bech32.ConvertAndEncode(prefix, bs)
    52  		if err != nil {
    53  			panic(err)
    54  		}
    55  
    56  		out.Formats[i] = bech32Addr
    57  	}
    58  
    59  	return out
    60  }
    61  
    62  func (bo bech32Output) String() string {
    63  	out := make([]string, len(bo.Formats))
    64  
    65  	for i, format := range bo.Formats {
    66  		out[i] = fmt.Sprintf("  - %s", format)
    67  	}
    68  
    69  	return fmt.Sprintf("Bech32 Formats:\n%s", strings.Join(out, "\n"))
    70  }
    71  
    72  // ParseKeyStringCommand parses an address from hex to bech32 and vice versa.
    73  func ParseKeyStringCommand() *cobra.Command {
    74  	cmd := &cobra.Command{
    75  		Use:   "parse <hex-or-bech32-address>",
    76  		Short: "Parse address from hex to bech32 and vice versa",
    77  		Long: `Convert and print to stdout key addresses and fingerprints from
    78  hexadecimal into bech32 cosmos prefixed format and vice versa.
    79  `,
    80  		Args: cobra.ExactArgs(1),
    81  		RunE: parseKey,
    82  	}
    83  
    84  	return cmd
    85  }
    86  
    87  func parseKey(cmd *cobra.Command, args []string) error {
    88  	config, _ := sdk.GetSealedConfig(cmd.Context())
    89  	return doParseKey(cmd, config, args)
    90  }
    91  
    92  func doParseKey(cmd *cobra.Command, config *sdk.Config, args []string) error {
    93  	addr := strings.TrimSpace(args[0])
    94  	outstream := cmd.OutOrStdout()
    95  
    96  	if len(addr) == 0 {
    97  		return errors.New("couldn't parse empty input")
    98  	}
    99  
   100  	output, _ := cmd.Flags().GetString(cli.OutputFlag)
   101  	if !(runFromBech32(outstream, addr, output) || runFromHex(config, outstream, addr, output)) {
   102  		return errors.New("couldn't find valid bech32 nor hex data")
   103  	}
   104  
   105  	return nil
   106  }
   107  
   108  // print info from bech32
   109  func runFromBech32(w io.Writer, bech32str, output string) bool {
   110  	hrp, bz, err := bech32.DecodeAndConvert(bech32str)
   111  	if err != nil {
   112  		return false
   113  	}
   114  
   115  	displayParseKeyInfo(w, newHexOutput(hrp, bz), output)
   116  
   117  	return true
   118  }
   119  
   120  // print info from hex
   121  func runFromHex(config *sdk.Config, w io.Writer, hexstr, output string) bool {
   122  	bz, err := hex.DecodeString(hexstr)
   123  	if err != nil {
   124  		return false
   125  	}
   126  
   127  	displayParseKeyInfo(w, newBech32Output(config, bz), output)
   128  
   129  	return true
   130  }
   131  
   132  func displayParseKeyInfo(w io.Writer, stringer fmt.Stringer, output string) {
   133  	var (
   134  		err error
   135  		out []byte
   136  	)
   137  
   138  	switch output {
   139  	case OutputFormatText:
   140  		out, err = yaml.Marshal(&stringer)
   141  
   142  	case OutputFormatJSON:
   143  		out, err = KeysCdc.MarshalJSON(stringer)
   144  	}
   145  
   146  	if err != nil {
   147  		panic(err)
   148  	}
   149  
   150  	_, _ = fmt.Fprintln(w, string(out))
   151  }