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"
"path/filepath"
"strings"
"syscall"
"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/pkg/compiler"
"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/wallet"
"github.com/urfave/cli"
"golang.org/x/crypto/ssh/terminal"
"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)
}
fmt.Fprintf(ctx.App.Writer, "Enter account %s password > ", address.Uint160ToString(addr))
rawPass, err := terminal.ReadPassword(syscall.Stdin)
rawPass, err := input.ReadPassword(ctx.App.Writer,
fmt.Sprintf("Enter account %s password > ", address.Uint160ToString(addr)))
fmt.Fprintln(ctx.App.Writer)
if err != nil {
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"
"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/pkg/crypto/keys"
"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))
}
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
} else if err := acc.Decrypt(pass); err != nil {
return nil, err

View file

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