diff --git a/cmd/wallet.go b/cmd/wallet.go index 031f1e6..854596c 100644 --- a/cmd/wallet.go +++ b/cmd/wallet.go @@ -10,6 +10,7 @@ import ( "strings" "github.com/btcsuite/btcutil/base58" + "github.com/cosmos/btcutil/bech32" "github.com/hashicorp/go-secure-stdlib/password" "github.com/jedib0t/go-pretty/v6/table" "github.com/spacemeshos/go-spacemesh/common/types" @@ -33,6 +34,9 @@ var ( // printBase58 indicates that keys should be printed in base58 format. printBase58 bool + // printHex indicates that keys should be printed in Hex format. + printHex bool + // printParent indicates that the parent key should be printed. printParent bool @@ -141,8 +145,9 @@ sure the device is connected, unlocked, and the Spacemesh app is open.`, // readCmd reads an existing wallet file. var readCmd = &cobra.Command{ - Use: "read [wallet file] [--full/-f] [--private/-p] [--base58]", - Short: "Reads an existing wallet file", + Use: "read [wallet file] [--full/-f] [--private/-p] [--parent] [--base58] [--hex]", + DisableFlagsInUseLine: true, + Short: "Reads an existing wallet file", Long: `This command can be used to verify whether an existing wallet file can be successfully read and decrypted, whether the password to open the file is correct, etc. It prints the accounts from the wallet file. By default it does not print private keys. @@ -151,24 +156,11 @@ keys in base58 format rather than hexadecimal. Add --parent to print parent key only child keys).`, Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { - walletFn := args[0] - - // make sure the file exists - f, err := os.Open(walletFn) - cobra.CheckErr(err) - defer f.Close() - - // get the password - fmt.Print("Enter wallet password: ") - password, err := password.Read(os.Stdin) - fmt.Println() - cobra.CheckErr(err) - - // attempt to read it - wk := wallet.NewKey(wallet.WithPasswordOnly([]byte(password))) - w, err := wk.Open(f, debug) + w, err := internal.LoadWallet(args[0], debug) cobra.CheckErr(err) + caption := make([]string, 0, 2) + maxWidth := 20 widthEnforcer := func(col string, maxLen int) string { if len(col) <= maxLen { return col @@ -179,55 +171,51 @@ only child keys).`, return fmt.Sprintf("%s..%s", col[:maxLen-7], col[len(col)-5:]) } - t := table.NewWriter() - t.SetOutputMirror(os.Stdout) - t.SetTitle("Wallet Contents") - caption := "" - if printPrivate { - caption = fmt.Sprintf("Mnemonic: %s", w.Mnemonic()) - } - if !printFull { - if printPrivate { - caption += "\n" - } - caption += "To print full keys, use the --full flag." - } - t.SetCaption(caption) - maxWidth := 20 - if printFull { - // full key is 64 bytes which is 128 chars in hex, need to print at least this much - maxWidth = 150 + header := table.Row{"pubkey", "path", "name", "created"} + colCfgs := []table.ColumnConfig{ + {Number: 1, WidthMax: maxWidth, WidthMaxEnforcer: widthEnforcer}, } + // TODO: add spacemesh address format (bech32) // https://github.com/spacemeshos/smcli/issues/38 if printPrivate { - t.AppendHeader(table.Row{ - "pubkey", - "privkey", - "path", - "name", - "created", - }) - t.SetColumnConfigs([]table.ColumnConfig{ - {Number: 1, WidthMax: maxWidth, WidthMaxEnforcer: widthEnforcer}, - {Number: 2, WidthMax: maxWidth, WidthMaxEnforcer: widthEnforcer}, + caption = append(caption, fmt.Sprintf("Mnemonic: %s", w.Mnemonic())) + header = append(header[:2], header[1:]...) + header[1] = "privkey" + colCfgs = append(colCfgs, table.ColumnConfig{ + Number: 2, WidthMax: maxWidth, WidthMaxEnforcer: widthEnforcer, }) + } + + if printFull { + // full key is 64 bytes which is 128 chars in hex, need to print at least this much + maxWidth = 150 } else { - t.AppendHeader(table.Row{ - "pubkey", - "path", - "name", - "created", - }) - t.SetColumnConfigs([]table.ColumnConfig{ - {Number: 1, WidthMax: maxWidth, WidthMaxEnforcer: widthEnforcer}, - }) + caption = append(caption, "To print full keys, use the --full flag.") } + t := table.NewWriter() + t.SetOutputMirror(os.Stdout) + t.SetTitle("Wallet Contents") + t.SetCaption(strings.Join(caption, "\n")) + t.AppendHeader(header) + t.SetColumnConfigs(colCfgs) + // set the encoder - encoder := hex.EncodeToString - if printBase58 { + var encoder func([]byte) string + switch { + case printBase58: encoder = base58.Encode + case printHex: + encoder = hex.EncodeToString + default: + encoder = func(data []byte) string { + dataConverted, err := bech32.ConvertBits(data, 8, 5, true) + cobra.CheckErr(err) + encoded, err := bech32.Encode(types.NetworkHRP(), dataConverted) + cobra.CheckErr(err) + return encoded + } } privKeyEncoder := func(privKey []byte) string { @@ -325,7 +313,8 @@ func init() { walletCmd.AddCommand(addrCmd) readCmd.Flags().BoolVarP(&printPrivate, "private", "p", false, "Print private keys") readCmd.Flags().BoolVarP(&printFull, "full", "f", false, "Print full keys (no abbreviation)") - readCmd.Flags().BoolVar(&printBase58, "base58", false, "Print keys in base58 (rather than hex)") + readCmd.Flags().BoolVar(&printBase58, "base58", false, "Print keys in base58 (rather than bech32)") + readCmd.Flags().BoolVar(&printHex, "hex", false, "Print keys in hex (rather than bech32)") readCmd.Flags().BoolVar(&printParent, "parent", false, "Print parent key (not only child keys)") readCmd.PersistentFlags().BoolVarP(&debug, "debug", "d", false, "enable debug mode") createCmd.Flags().BoolVarP(&useLedger, "ledger", "l", false, "Create a wallet using a Ledger device") diff --git a/go.mod b/go.mod index 75f085b..732337c 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.18 require ( github.com/btcsuite/btcutil v1.0.2 + github.com/cosmos/btcutil v1.0.5 github.com/jedib0t/go-pretty/v6 v6.4.6 github.com/spacemeshos/economics v0.1.0 github.com/spacemeshos/go-spacemesh v0.3.3-beta.0.0.20230710094357-ba923401156a @@ -15,7 +16,6 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/c0mm4nd/go-ripemd v0.0.0-20200326052756-bd1759ad7d10 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/cosmos/btcutil v1.0.5 // indirect github.com/go-llsqlite/llsqlite v0.0.0-20230612031458-a9e271fe723a // indirect github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.3 // indirect