cli/wallet: allow to read wallet from stdin where it's possible

Unfortunately, testing this code is not possible without an additional wrapper
in `input`, but adding it just to test this seems to be too excessive. Fixes
This commit is contained in:
Roman Khimov 2021-12-07 19:36:02 +03:00
parent 06fc450789
commit 5196558056
7 changed files with 38 additions and 14 deletions

View file

@ -12,7 +12,7 @@ import (
) )
func signStoredTransaction(ctx *cli.Context) error { func signStoredTransaction(ctx *cli.Context) error {
wall, err := openWallet(ctx.String("wallet")) wall, err := readWallet(ctx.String("wallet"))
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }

View file

@ -150,7 +150,7 @@ func removeNEP11Token(ctx *cli.Context) error {
func getNEP11Balance(ctx *cli.Context) error { func getNEP11Balance(ctx *cli.Context) error {
var accounts []*wallet.Account var accounts []*wallet.Account
wall, err := openWallet(ctx.String("wallet")) wall, err := readWallet(ctx.String("wallet"))
if err != nil { if err != nil {
return cli.NewExitError(fmt.Errorf("bad wallet: %w", err), 1) return cli.NewExitError(fmt.Errorf("bad wallet: %w", err), 1)
} }

View file

@ -142,7 +142,7 @@ func newNEP17Commands() []cli.Command {
func getNEP17Balance(ctx *cli.Context) error { func getNEP17Balance(ctx *cli.Context) error {
var accounts []*wallet.Account var accounts []*wallet.Account
wall, err := openWallet(ctx.String("wallet")) wall, err := readWallet(ctx.String("wallet"))
if err != nil { if err != nil {
return cli.NewExitError(fmt.Errorf("bad wallet: %w", err), 1) return cli.NewExitError(fmt.Errorf("bad wallet: %w", err), 1)
} }
@ -346,7 +346,7 @@ func printNEP17Info(ctx *cli.Context) error {
} }
func printNEPInfo(ctx *cli.Context, standard string) error { func printNEPInfo(ctx *cli.Context, standard string) error {
wall, err := openWallet(ctx.String("wallet")) wall, err := readWallet(ctx.String("wallet"))
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
@ -403,7 +403,7 @@ func removeNEPToken(ctx *cli.Context, standard string) error {
} }
func multiTransferNEP17(ctx *cli.Context) error { func multiTransferNEP17(ctx *cli.Context) error {
wall, err := openWallet(ctx.String("wallet")) wall, err := readWallet(ctx.String("wallet"))
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
@ -489,7 +489,7 @@ func transferNEP17(ctx *cli.Context) error {
} }
func transferNEP(ctx *cli.Context, standard string) error { func transferNEP(ctx *cli.Context, standard string) error {
wall, err := openWallet(ctx.String("wallet")) wall, err := readWallet(ctx.String("wallet"))
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }

View file

@ -83,7 +83,7 @@ func handleUnregister(ctx *cli.Context) error {
} }
func handleCandidate(ctx *cli.Context, method string, sysGas int64) error { func handleCandidate(ctx *cli.Context, method string, sysGas int64) error {
wall, err := openWallet(ctx.String("wallet")) wall, err := readWallet(ctx.String("wallet"))
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
@ -138,7 +138,7 @@ func handleCandidate(ctx *cli.Context, method string, sysGas int64) error {
} }
func handleVote(ctx *cli.Context) error { func handleVote(ctx *cli.Context) error {
wall, err := openWallet(ctx.String("wallet")) wall, err := readWallet(ctx.String("wallet"))
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }

View file

@ -2,9 +2,11 @@ package wallet
import ( import (
"encoding/hex" "encoding/hex"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"io" "io"
"os"
"strings" "strings"
"github.com/nspcc-dev/neo-go/cli/flags" "github.com/nspcc-dev/neo-go/cli/flags"
@ -23,12 +25,13 @@ import (
var ( var (
errNoPath = errors.New("target path where the wallet should be stored is mandatory and should be passed using (--wallet, -w) flags") errNoPath = errors.New("target path where the wallet should be stored is mandatory and should be passed using (--wallet, -w) flags")
errPhraseMismatch = errors.New("the entered pass-phrases do not match. Maybe you have misspelled them") errPhraseMismatch = errors.New("the entered pass-phrases do not match. Maybe you have misspelled them")
errNoStdin = errors.New("can't read wallet from stdin for this command")
) )
var ( var (
walletPathFlag = cli.StringFlag{ walletPathFlag = cli.StringFlag{
Name: "wallet, w", Name: "wallet, w",
Usage: "Target location of the wallet file.", Usage: "Target location of the wallet file ('-' to read from stdin).",
} }
wifFlag = cli.StringFlag{ wifFlag = cli.StringFlag{
Name: "wif", Name: "wif",
@ -249,7 +252,7 @@ func NewCommands() []cli.Command {
} }
func claimGas(ctx *cli.Context) error { func claimGas(ctx *cli.Context) error {
wall, err := openWallet(ctx.String("wallet")) wall, err := readWallet(ctx.String("wallet"))
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
@ -332,7 +335,7 @@ func addAccount(ctx *cli.Context) error {
} }
func exportKeys(ctx *cli.Context) error { func exportKeys(ctx *cli.Context) error {
wall, err := openWallet(ctx.String("wallet")) wall, err := readWallet(ctx.String("wallet"))
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
@ -560,7 +563,7 @@ func askForConsent(w io.Writer) bool {
} }
func dumpWallet(ctx *cli.Context) error { func dumpWallet(ctx *cli.Context) error {
wall, err := openWallet(ctx.String("wallet")) wall, err := readWallet(ctx.String("wallet"))
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
@ -582,7 +585,7 @@ func dumpWallet(ctx *cli.Context) error {
} }
func dumpKeys(ctx *cli.Context) error { func dumpKeys(ctx *cli.Context) error {
wall, err := openWallet(ctx.String("wallet")) wall, err := readWallet(ctx.String("wallet"))
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
@ -683,6 +686,23 @@ func openWallet(path string) (*wallet.Wallet, error) {
if len(path) == 0 { if len(path) == 0 {
return nil, errNoPath return nil, errNoPath
} }
if path == "-" {
return nil, errNoStdin
}
return wallet.NewWalletFromFile(path)
}
func readWallet(path string) (*wallet.Wallet, error) {
if len(path) == 0 {
return nil, errNoPath
}
if path == "-" {
w := &wallet.Wallet{}
if err := json.NewDecoder(os.Stdin).Decode(w); err != nil {
return nil, fmt.Errorf("js %s", err)
}
return w, nil
}
return wallet.NewWalletFromFile(path) return wallet.NewWalletFromFile(path)
} }

View file

@ -75,6 +75,9 @@ func TestWalletInit(t *testing.T) {
}) })
t.Run("CreateAccount", func(t *testing.T) { t.Run("CreateAccount", func(t *testing.T) {
t.Run("stdin", func(t *testing.T) {
e.RunWithError(t, "neo-go", "wallet", "create", "--wallet", "-")
})
e.In.WriteString("testname\r") e.In.WriteString("testname\r")
e.In.WriteString("testpass\r") e.In.WriteString("testpass\r")
e.In.WriteString("testpass\r") e.In.WriteString("testpass\r")

View file

@ -83,7 +83,8 @@ see [compiler documentation](compiler.md).
deploy` and `contract invokefunction`). Wallet management (creating wallet, deploy` and `contract invokefunction`). Wallet management (creating wallet,
adding addresses/keys to it) is available there as well as wallet-related adding addresses/keys to it) is available there as well as wallet-related
functions like NEP-17 transfers, NEO votes, multi-signature signing and other functions like NEP-17 transfers, NEO votes, multi-signature signing and other
things. things. For all commands requiring read-only wallet (like `dump-keys`) a
special `-` path can be used to read the wallet from the standard input.
### Wallet management ### Wallet management