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 }