cli: move input handling to a separate package

This commit is contained in:
Evgenii Stratonikov 2020-08-31 12:22:09 +03:00
parent 758a88a813
commit 0dda247719
5 changed files with 60 additions and 31 deletions

44
cli/input/input.go Normal file
View file

@ -0,0 +1,44 @@
package input
import (
"bufio"
"fmt"
"io"
"os"
"strings"
"syscall"
"golang.org/x/crypto/ssh/terminal"
)
// Terminal is a terminal used for input. If `nil`, stdin is used.
var Terminal *terminal.Terminal
// ReadLine reads line from the input without trailing '\n'
func ReadLine(w io.Writer, prompt string) (string, error) {
if Terminal != nil {
_, err := Terminal.Write([]byte(prompt))
if err != nil {
return "", err
}
raw, err := Terminal.ReadLine()
return strings.TrimRight(raw, "\n"), err
}
fmt.Fprint(w, prompt)
buf := bufio.NewReader(os.Stdin)
return buf.ReadString('\n')
}
// ReadPassword reads user password with prompt.
func ReadPassword(w io.Writer, prompt string) (string, error) {
if Terminal != nil {
return Terminal.ReadPassword(prompt)
}
fmt.Fprint(w, prompt)
rawPass, err := terminal.ReadPassword(syscall.Stdin)
if err != nil {
return "", err
}
fmt.Fprintln(w)
return strings.TrimRight(string(rawPass), "\n"), nil
}

View file

@ -9,9 +9,9 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"syscall"
"github.com/nspcc-dev/neo-go/cli/flags" "github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/input"
"github.com/nspcc-dev/neo-go/cli/options" "github.com/nspcc-dev/neo-go/cli/options"
"github.com/nspcc-dev/neo-go/pkg/compiler" "github.com/nspcc-dev/neo-go/pkg/compiler"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
@ -25,7 +25,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/wallet" "github.com/nspcc-dev/neo-go/pkg/wallet"
"github.com/urfave/cli" "github.com/urfave/cli"
"golang.org/x/crypto/ssh/terminal"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
) )
@ -680,8 +679,8 @@ func getAccFromContext(ctx *cli.Context) (*wallet.Account, error) {
return nil, cli.NewExitError(fmt.Errorf("wallet contains no account for '%s'", address.Uint160ToString(addr)), 1) return nil, cli.NewExitError(fmt.Errorf("wallet contains no account for '%s'", address.Uint160ToString(addr)), 1)
} }
fmt.Fprintf(ctx.App.Writer, "Enter account %s password > ", address.Uint160ToString(addr)) rawPass, err := input.ReadPassword(ctx.App.Writer,
rawPass, err := terminal.ReadPassword(syscall.Stdin) fmt.Sprintf("Enter account %s password > ", address.Uint160ToString(addr)))
fmt.Fprintln(ctx.App.Writer) fmt.Fprintln(ctx.App.Writer)
if err != nil { if err != nil {
return nil, cli.NewExitError(err, 1) return nil, cli.NewExitError(err, 1)

1
cli/testdata/testwallet.json vendored Normal file
View file

@ -0,0 +1 @@
{"version":"3.0","accounts":[{"address":"NNuJqXDnRqvwgzhSzhH4jnVFWB1DyZ34EM","key":"6PYT6enT6eh4gu4ew3Mx58pFFDQNhuR1qQPuU594Eo5u4sA2ZvE4MqJV12","label":"kek","contract":{"script":"DCECl3UyEIq6T5RRIXS6z4tNdZPTzQ7NvXyx7FwK05d9UyYLQZVEDXg=","parameters":[{"name":"parameter0","type":"Signature"}],"deployed":false},"lock":false,"isdefault":false}],"scrypt":{"n":16384,"r":8,"p":8},"extra":{"Tokens":null}}

View file

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"github.com/nspcc-dev/neo-go/cli/flags" "github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/input"
"github.com/nspcc-dev/neo-go/cli/options" "github.com/nspcc-dev/neo-go/cli/options"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/encoding/address"
@ -178,7 +179,8 @@ func getDecryptedAccount(ctx *cli.Context, wall *wallet.Wallet, addr util.Uint16
return nil, fmt.Errorf("can't find account for the address: %s", address.Uint160ToString(addr)) return nil, fmt.Errorf("can't find account for the address: %s", address.Uint160ToString(addr))
} }
if pass, err := readPassword(ctx.App.Writer, "Password > "); err != nil { if pass, err := input.ReadPassword(ctx.App.Writer, "Password > "); err != nil {
fmt.Println("ERROR", pass, err)
return nil, err return nil, err
} else if err := acc.Decrypt(pass); err != nil { } else if err := acc.Decrypt(pass); err != nil {
return nil, err return nil, err

View file

@ -1,16 +1,14 @@
package wallet package wallet
import ( import (
"bufio"
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt" "fmt"
"io" "io"
"os"
"strings" "strings"
"syscall"
"github.com/nspcc-dev/neo-go/cli/flags" "github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/input"
"github.com/nspcc-dev/neo-go/cli/options" "github.com/nspcc-dev/neo-go/cli/options"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/encoding/address"
@ -18,7 +16,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/wallet" "github.com/nspcc-dev/neo-go/pkg/wallet"
"github.com/urfave/cli" "github.com/urfave/cli"
"golang.org/x/crypto/ssh/terminal"
) )
var ( var (
@ -266,7 +263,7 @@ func convertWallet(ctx *cli.Context) error {
for _, acc := range wall.Accounts { for _, acc := range wall.Accounts {
address.Prefix = address.NEO2Prefix address.Prefix = address.NEO2Prefix
pass, err := readPassword(ctx.App.Writer, fmt.Sprintf("Enter passphrase for account %s (label '%s') > ", acc.Address, acc.Label)) pass, err := input.ReadPassword(ctx.App.Writer, fmt.Sprintf("Enter passphrase for account %s (label '%s') > ", acc.Address, acc.Label))
if err != nil { if err != nil {
return cli.NewExitError(err, -1) return cli.NewExitError(err, -1)
} else if err := acc.Decrypt(pass); err != nil { } else if err := acc.Decrypt(pass); err != nil {
@ -348,7 +345,7 @@ loop:
for _, wif := range wifs { for _, wif := range wifs {
if decrypt { if decrypt {
pass, err := readPassword(ctx.App.Writer, "Enter password > ") pass, err := input.ReadPassword(ctx.App.Writer, "Enter password > ")
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
@ -518,9 +515,7 @@ func removeAccount(ctx *cli.Context) error {
} }
func askForConsent(w io.Writer) bool { func askForConsent(w io.Writer) bool {
fmt.Fprintln(w, "Are you sure? [y/N]: ") response, err := input.ReadLine(w, "Are you sure? [y/N]: ")
reader := bufio.NewReader(os.Stdin)
response, err := reader.ReadString('\n')
if err == nil { if err == nil {
response = strings.ToLower(strings.TrimSpace(response)) response = strings.ToLower(strings.TrimSpace(response))
if response == "y" || response == "yes" { if response == "y" || response == "yes" {
@ -537,7 +532,7 @@ func dumpWallet(ctx *cli.Context) error {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
if ctx.Bool("decrypt") { if ctx.Bool("decrypt") {
pass, err := readPassword(ctx.App.Writer, "Enter wallet password > ") pass, err := input.ReadPassword(ctx.App.Writer, "Enter wallet password > ")
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
@ -578,14 +573,12 @@ func createWallet(ctx *cli.Context) error {
} }
func readAccountInfo(w io.Writer) (string, string, error) { func readAccountInfo(w io.Writer) (string, string, error) {
buf := bufio.NewReader(os.Stdin) rawName, _ := input.ReadLine(w, "Enter the name of the account > ")
fmt.Fprint(w, "Enter the name of the account > ") phrase, err := input.ReadPassword(w, "Enter passphrase > ")
rawName, _ := buf.ReadBytes('\n')
phrase, err := readPassword(w, "Enter passphrase > ")
if err != nil { if err != nil {
return "", "", err return "", "", err
} }
phraseCheck, err := readPassword(w, "Confirm passphrase > ") phraseCheck, err := input.ReadPassword(w, "Confirm passphrase > ")
if err != nil { if err != nil {
return "", "", err return "", "", err
} }
@ -617,7 +610,7 @@ func newAccountFromWIF(w io.Writer, wif string) (*wallet.Account, error) {
// note: NEP2 strings always have length of 58 even though // note: NEP2 strings always have length of 58 even though
// base58 strings can have different lengths even if slice lengths are equal // base58 strings can have different lengths even if slice lengths are equal
if len(wif) == 58 { if len(wif) == 58 {
pass, err := readPassword(w, "Enter password > ") pass, err := input.ReadPassword(w, "Enter password > ")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -655,16 +648,6 @@ func addAccountAndSave(w *wallet.Wallet, acc *wallet.Account) error {
return w.Save() return w.Save()
} }
func readPassword(w io.Writer, prompt string) (string, error) {
fmt.Fprint(w, prompt)
rawPass, err := terminal.ReadPassword(syscall.Stdin)
fmt.Fprintln(w)
if err != nil {
return "", err
}
return strings.TrimRight(string(rawPass), "\n"), nil
}
func fmtPrintWallet(w io.Writer, wall *wallet.Wallet) { func fmtPrintWallet(w io.Writer, wall *wallet.Wallet) {
b, _ := wall.JSON() b, _ := wall.JSON()
fmt.Fprintln(w, "") fmt.Fprintln(w, "")