forked from cerc-io/plugeth
		
	cmd/geth, cmd/utils: improve input handling
These changes make prompting behave consistently on all platforms: * The input buffer is now global. Buffering was previously set up for each prompt, which can cause weird behaviour, e.g. when running "geth account update <input.txt" where input.txt contains three lines. In this case, the first password prompt would fill up the buffer with all lines and then use only the first one. * Print the "unsupported terminal" warning only once. Now that stdin prompting has global state, we can use it to track the warning there. * Work around small liner issues, particularly on Windows. Prompting didn't work under most of the third-party terminal emulators on Windows because liner assumes line editing is always available.
This commit is contained in:
		
							parent
							
								
									83877a0f9d
								
							
						
					
					
						commit
						dff9b4246f
					
				| @ -116,7 +116,7 @@ func exportChain(ctx *cli.Context) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func removeDB(ctx *cli.Context) { | func removeDB(ctx *cli.Context) { | ||||||
| 	confirm, err := utils.PromptConfirm("Remove local database?") | 	confirm, err := utils.Stdin.ConfirmPrompt("Remove local database?") | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		utils.Fatalf("%v", err) | 		utils.Fatalf("%v", err) | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -17,7 +17,6 @@ | |||||||
| package main | package main | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"bufio" |  | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"math/big" | 	"math/big" | ||||||
| 	"os" | 	"os" | ||||||
| @ -46,30 +45,6 @@ var ( | |||||||
| 	exit           = regexp.MustCompile("^\\s*exit\\s*;*\\s*$") | 	exit           = regexp.MustCompile("^\\s*exit\\s*;*\\s*$") | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type prompter interface { |  | ||||||
| 	AppendHistory(string) |  | ||||||
| 	Prompt(p string) (string, error) |  | ||||||
| 	PasswordPrompt(p string) (string, error) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type dumbterm struct{ r *bufio.Reader } |  | ||||||
| 
 |  | ||||||
| func (r dumbterm) Prompt(p string) (string, error) { |  | ||||||
| 	fmt.Print(p) |  | ||||||
| 	line, err := r.r.ReadString('\n') |  | ||||||
| 	return strings.TrimSuffix(line, "\n"), err |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (r dumbterm) PasswordPrompt(p string) (string, error) { |  | ||||||
| 	fmt.Println("!! Unsupported terminal, password will echo.") |  | ||||||
| 	fmt.Print(p) |  | ||||||
| 	input, err := bufio.NewReader(os.Stdin).ReadString('\n') |  | ||||||
| 	fmt.Println() |  | ||||||
| 	return input, err |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (r dumbterm) AppendHistory(string) {} |  | ||||||
| 
 |  | ||||||
| type jsre struct { | type jsre struct { | ||||||
| 	re         *re.JSRE | 	re         *re.JSRE | ||||||
| 	stack      *node.Node | 	stack      *node.Node | ||||||
| @ -78,7 +53,6 @@ type jsre struct { | |||||||
| 	atexit     func() | 	atexit     func() | ||||||
| 	corsDomain string | 	corsDomain string | ||||||
| 	client     rpc.Client | 	client     rpc.Client | ||||||
| 	prompter |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func makeCompleter(re *jsre) liner.WordCompleter { | func makeCompleter(re *jsre) liner.WordCompleter { | ||||||
| @ -106,27 +80,11 @@ func newLightweightJSRE(docRoot string, client rpc.Client, datadir string, inter | |||||||
| 	js := &jsre{ps1: "> "} | 	js := &jsre{ps1: "> "} | ||||||
| 	js.wait = make(chan *big.Int) | 	js.wait = make(chan *big.Int) | ||||||
| 	js.client = client | 	js.client = client | ||||||
| 
 |  | ||||||
| 	js.re = re.New(docRoot) | 	js.re = re.New(docRoot) | ||||||
| 	if err := js.apiBindings(); err != nil { | 	if err := js.apiBindings(); err != nil { | ||||||
| 		utils.Fatalf("Unable to initialize console - %v", err) | 		utils.Fatalf("Unable to initialize console - %v", err) | ||||||
| 	} | 	} | ||||||
| 
 | 	js.setupInput(datadir) | ||||||
| 	if !liner.TerminalSupported() || !interactive { |  | ||||||
| 		js.prompter = dumbterm{bufio.NewReader(os.Stdin)} |  | ||||||
| 	} else { |  | ||||||
| 		lr := liner.NewLiner() |  | ||||||
| 		js.withHistory(datadir, func(hist *os.File) { lr.ReadHistory(hist) }) |  | ||||||
| 		lr.SetCtrlCAborts(true) |  | ||||||
| 		lr.SetWordCompleter(makeCompleter(js)) |  | ||||||
| 		lr.SetTabCompletionStyle(liner.TabPrints) |  | ||||||
| 		js.prompter = lr |  | ||||||
| 		js.atexit = func() { |  | ||||||
| 			js.withHistory(datadir, func(hist *os.File) { hist.Truncate(0); lr.WriteHistory(hist) }) |  | ||||||
| 			lr.Close() |  | ||||||
| 			close(js.wait) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return js | 	return js | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -136,30 +94,29 @@ func newJSRE(stack *node.Node, docRoot, corsDomain string, client rpc.Client, in | |||||||
| 	js.corsDomain = corsDomain | 	js.corsDomain = corsDomain | ||||||
| 	js.wait = make(chan *big.Int) | 	js.wait = make(chan *big.Int) | ||||||
| 	js.client = client | 	js.client = client | ||||||
| 
 |  | ||||||
| 	js.re = re.New(docRoot) | 	js.re = re.New(docRoot) | ||||||
| 	if err := js.apiBindings(); err != nil { | 	if err := js.apiBindings(); err != nil { | ||||||
| 		utils.Fatalf("Unable to connect - %v", err) | 		utils.Fatalf("Unable to connect - %v", err) | ||||||
| 	} | 	} | ||||||
| 
 | 	js.setupInput(stack.DataDir()) | ||||||
| 	if !liner.TerminalSupported() || !interactive { |  | ||||||
| 		js.prompter = dumbterm{bufio.NewReader(os.Stdin)} |  | ||||||
| 	} else { |  | ||||||
| 		lr := liner.NewLiner() |  | ||||||
| 		js.withHistory(stack.DataDir(), func(hist *os.File) { lr.ReadHistory(hist) }) |  | ||||||
| 		lr.SetCtrlCAborts(true) |  | ||||||
| 		lr.SetWordCompleter(makeCompleter(js)) |  | ||||||
| 		lr.SetTabCompletionStyle(liner.TabPrints) |  | ||||||
| 		js.prompter = lr |  | ||||||
| 		js.atexit = func() { |  | ||||||
| 			js.withHistory(stack.DataDir(), func(hist *os.File) { hist.Truncate(0); lr.WriteHistory(hist) }) |  | ||||||
| 			lr.Close() |  | ||||||
| 			close(js.wait) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return js | 	return js | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (self *jsre) setupInput(datadir string) { | ||||||
|  | 	self.withHistory(datadir, func(hist *os.File) { utils.Stdin.ReadHistory(hist) }) | ||||||
|  | 	utils.Stdin.SetCtrlCAborts(true) | ||||||
|  | 	utils.Stdin.SetWordCompleter(makeCompleter(self)) | ||||||
|  | 	utils.Stdin.SetTabCompletionStyle(liner.TabPrints) | ||||||
|  | 	self.atexit = func() { | ||||||
|  | 		self.withHistory(datadir, func(hist *os.File) { | ||||||
|  | 			hist.Truncate(0) | ||||||
|  | 			utils.Stdin.WriteHistory(hist) | ||||||
|  | 		}) | ||||||
|  | 		utils.Stdin.Close() | ||||||
|  | 		close(self.wait) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (self *jsre) batch(statement string) { | func (self *jsre) batch(statement string) { | ||||||
| 	err := self.re.EvalAndPrettyPrint(statement) | 	err := self.re.EvalAndPrettyPrint(statement) | ||||||
| 
 | 
 | ||||||
| @ -290,7 +247,7 @@ func (js *jsre) apiBindings() error { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (self *jsre) AskPassword() (string, bool) { | func (self *jsre) AskPassword() (string, bool) { | ||||||
| 	pass, err := self.PasswordPrompt("Passphrase: ") | 	pass, err := utils.Stdin.PasswordPrompt("Passphrase: ") | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "", false | 		return "", false | ||||||
| 	} | 	} | ||||||
| @ -315,7 +272,7 @@ func (self *jsre) ConfirmTransaction(tx string) bool { | |||||||
| 
 | 
 | ||||||
| func (self *jsre) UnlockAccount(addr []byte) bool { | func (self *jsre) UnlockAccount(addr []byte) bool { | ||||||
| 	fmt.Printf("Please unlock account %x.\n", addr) | 	fmt.Printf("Please unlock account %x.\n", addr) | ||||||
| 	pass, err := self.PasswordPrompt("Passphrase: ") | 	pass, err := utils.Stdin.PasswordPrompt("Passphrase: ") | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return false | 		return false | ||||||
| 	} | 	} | ||||||
| @ -365,7 +322,7 @@ func (self *jsre) interactive() { | |||||||
| 	go func() { | 	go func() { | ||||||
| 		defer close(inputln) | 		defer close(inputln) | ||||||
| 		for { | 		for { | ||||||
| 			line, err := self.Prompt(<-prompt) | 			line, err := utils.Stdin.Prompt(<-prompt) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				if err == liner.ErrPromptAborted { // ctrl-C
 | 				if err == liner.ErrPromptAborted { // ctrl-C
 | ||||||
| 					self.resetPrompt() | 					self.resetPrompt() | ||||||
| @ -404,7 +361,7 @@ func (self *jsre) interactive() { | |||||||
| 			self.setIndent() | 			self.setIndent() | ||||||
| 			if indentCount <= 0 { | 			if indentCount <= 0 { | ||||||
| 				if mustLogInHistory(str) { | 				if mustLogInHistory(str) { | ||||||
| 					self.AppendHistory(str[:len(str)-1]) | 					utils.Stdin.AppendHistory(str[:len(str)-1]) | ||||||
| 				} | 				} | ||||||
| 				self.parseInput(str) | 				self.parseInput(str) | ||||||
| 				str = "" | 				str = "" | ||||||
|  | |||||||
| @ -94,7 +94,7 @@ func testREPL(t *testing.T, config func(*eth.Config)) (string, *testjethre, *nod | |||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| 	} | 	} | ||||||
| 	// Create a networkless protocol stack
 | 	// Create a networkless protocol stack
 | ||||||
| 	stack, err := node.New(&node.Config{PrivateKey: testNodeKey, Name: "test", NoDiscovery: true}) | 	stack, err := node.New(&node.Config{DataDir: tmp, PrivateKey: testNodeKey, Name: "test", NoDiscovery: true}) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatalf("failed to create node: %v", err) | 		t.Fatalf("failed to create node: %v", err) | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -373,6 +373,7 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso | |||||||
| 	app.After = func(ctx *cli.Context) error { | 	app.After = func(ctx *cli.Context) error { | ||||||
| 		logger.Flush() | 		logger.Flush() | ||||||
| 		debug.Exit() | 		debug.Exit() | ||||||
|  | 		utils.Stdin.Close() // Resets terminal mode.
 | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @ -595,12 +596,12 @@ func getPassPhrase(prompt string, confirmation bool, i int, passwords []string) | |||||||
| 	} | 	} | ||||||
| 	// Otherwise prompt the user for the password
 | 	// Otherwise prompt the user for the password
 | ||||||
| 	fmt.Println(prompt) | 	fmt.Println(prompt) | ||||||
| 	password, err := utils.PromptPassword("Passphrase: ", true) | 	password, err := utils.Stdin.PasswordPrompt("Passphrase: ") | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		utils.Fatalf("Failed to read passphrase: %v", err) | 		utils.Fatalf("Failed to read passphrase: %v", err) | ||||||
| 	} | 	} | ||||||
| 	if confirmation { | 	if confirmation { | ||||||
| 		confirm, err := utils.PromptPassword("Repeat passphrase: ", false) | 		confirm, err := utils.Stdin.PasswordPrompt("Repeat passphrase: ") | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			utils.Fatalf("Failed to read passphrase confirmation: %v", err) | 			utils.Fatalf("Failed to read passphrase confirmation: %v", err) | ||||||
| 		} | 		} | ||||||
|  | |||||||
| @ -18,13 +18,11 @@ | |||||||
| package utils | package utils | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"bufio" |  | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"io" | 	"io" | ||||||
| 	"os" | 	"os" | ||||||
| 	"os/signal" | 	"os/signal" | ||||||
| 	"regexp" | 	"regexp" | ||||||
| 	"strings" |  | ||||||
| 
 | 
 | ||||||
| 	"github.com/ethereum/go-ethereum/common" | 	"github.com/ethereum/go-ethereum/common" | ||||||
| 	"github.com/ethereum/go-ethereum/core" | 	"github.com/ethereum/go-ethereum/core" | ||||||
| @ -34,17 +32,12 @@ import ( | |||||||
| 	"github.com/ethereum/go-ethereum/logger/glog" | 	"github.com/ethereum/go-ethereum/logger/glog" | ||||||
| 	"github.com/ethereum/go-ethereum/node" | 	"github.com/ethereum/go-ethereum/node" | ||||||
| 	"github.com/ethereum/go-ethereum/rlp" | 	"github.com/ethereum/go-ethereum/rlp" | ||||||
| 	"github.com/peterh/liner" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| const ( | const ( | ||||||
| 	importBatchSize = 2500 | 	importBatchSize = 2500 | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var ( |  | ||||||
| 	interruptCallbacks = []func(os.Signal){} |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| func openLogFile(Datadir string, filename string) *os.File { | func openLogFile(Datadir string, filename string) *os.File { | ||||||
| 	path := common.AbsolutePath(Datadir, filename) | 	path := common.AbsolutePath(Datadir, filename) | ||||||
| 	file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) | 	file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) | ||||||
| @ -54,49 +47,6 @@ func openLogFile(Datadir string, filename string) *os.File { | |||||||
| 	return file | 	return file | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func PromptConfirm(prompt string) (bool, error) { |  | ||||||
| 	var ( |  | ||||||
| 		input string |  | ||||||
| 		err   error |  | ||||||
| 	) |  | ||||||
| 	prompt = prompt + " [y/N] " |  | ||||||
| 
 |  | ||||||
| 	// if liner.TerminalSupported() {
 |  | ||||||
| 	// 	fmt.Println("term")
 |  | ||||||
| 	// 	lr := liner.NewLiner()
 |  | ||||||
| 	// 	defer lr.Close()
 |  | ||||||
| 	// 	input, err = lr.Prompt(prompt)
 |  | ||||||
| 	// } else {
 |  | ||||||
| 	fmt.Print(prompt) |  | ||||||
| 	input, err = bufio.NewReader(os.Stdin).ReadString('\n') |  | ||||||
| 	fmt.Println() |  | ||||||
| 	// }
 |  | ||||||
| 
 |  | ||||||
| 	if len(input) > 0 && strings.ToUpper(input[:1]) == "Y" { |  | ||||||
| 		return true, nil |  | ||||||
| 	} else { |  | ||||||
| 		return false, nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return false, err |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func PromptPassword(prompt string, warnTerm bool) (string, error) { |  | ||||||
| 	if liner.TerminalSupported() { |  | ||||||
| 		lr := liner.NewLiner() |  | ||||||
| 		defer lr.Close() |  | ||||||
| 		return lr.PasswordPrompt(prompt) |  | ||||||
| 	} |  | ||||||
| 	if warnTerm { |  | ||||||
| 		fmt.Println("!! Unsupported terminal, password will be echoed.") |  | ||||||
| 	} |  | ||||||
| 	fmt.Print(prompt) |  | ||||||
| 	input, err := bufio.NewReader(os.Stdin).ReadString('\n') |  | ||||||
| 	input = strings.TrimRight(input, "\r\n") |  | ||||||
| 	fmt.Println() |  | ||||||
| 	return input, err |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Fatalf formats a message to standard error and exits the program.
 | // Fatalf formats a message to standard error and exits the program.
 | ||||||
| // The message is also printed to standard output if standard error
 | // The message is also printed to standard output if standard error
 | ||||||
| // is redirected to a different file.
 | // is redirected to a different file.
 | ||||||
|  | |||||||
							
								
								
									
										98
									
								
								cmd/utils/input.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								cmd/utils/input.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,98 @@ | |||||||
|  | // Copyright 2016 The go-ethereum Authors
 | ||||||
|  | // This file is part of go-ethereum.
 | ||||||
|  | //
 | ||||||
|  | // go-ethereum is free software: you can redistribute it and/or modify
 | ||||||
|  | // it under the terms of the GNU General Public License as published by
 | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or
 | ||||||
|  | // (at your option) any later version.
 | ||||||
|  | //
 | ||||||
|  | // go-ethereum is distributed in the hope that it will be useful,
 | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | ||||||
|  | // GNU General Public License for more details.
 | ||||||
|  | //
 | ||||||
|  | // You should have received a copy of the GNU General Public License
 | ||||||
|  | // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
 | ||||||
|  | 
 | ||||||
|  | package utils | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"strings" | ||||||
|  | 
 | ||||||
|  | 	"github.com/peterh/liner" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Holds the stdin line reader.
 | ||||||
|  | // Only this reader may be used for input because it keeps
 | ||||||
|  | // an internal buffer.
 | ||||||
|  | var Stdin = newUserInputReader() | ||||||
|  | 
 | ||||||
|  | type userInputReader struct { | ||||||
|  | 	*liner.State | ||||||
|  | 	warned     bool | ||||||
|  | 	supported  bool | ||||||
|  | 	normalMode liner.ModeApplier | ||||||
|  | 	rawMode    liner.ModeApplier | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func newUserInputReader() *userInputReader { | ||||||
|  | 	r := new(userInputReader) | ||||||
|  | 	// Get the original mode before calling NewLiner.
 | ||||||
|  | 	// This is usually regular "cooked" mode where characters echo.
 | ||||||
|  | 	normalMode, _ := liner.TerminalMode() | ||||||
|  | 	// Turn on liner. It switches to raw mode.
 | ||||||
|  | 	r.State = liner.NewLiner() | ||||||
|  | 	rawMode, err := liner.TerminalMode() | ||||||
|  | 	if err != nil || !liner.TerminalSupported() { | ||||||
|  | 		r.supported = false | ||||||
|  | 	} else { | ||||||
|  | 		r.supported = true | ||||||
|  | 		r.normalMode = normalMode | ||||||
|  | 		r.rawMode = rawMode | ||||||
|  | 		// Switch back to normal mode while we're not prompting.
 | ||||||
|  | 		normalMode.ApplyMode() | ||||||
|  | 	} | ||||||
|  | 	return r | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *userInputReader) Prompt(prompt string) (string, error) { | ||||||
|  | 	if r.supported { | ||||||
|  | 		r.rawMode.ApplyMode() | ||||||
|  | 		defer r.normalMode.ApplyMode() | ||||||
|  | 	} else { | ||||||
|  | 		// liner tries to be smart about printing the prompt
 | ||||||
|  | 		// and doesn't print anything if input is redirected.
 | ||||||
|  | 		// Un-smart it by printing the prompt always.
 | ||||||
|  | 		fmt.Print(prompt) | ||||||
|  | 		prompt = "" | ||||||
|  | 		defer fmt.Println() | ||||||
|  | 	} | ||||||
|  | 	return r.State.Prompt(prompt) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *userInputReader) PasswordPrompt(prompt string) (passwd string, err error) { | ||||||
|  | 	if r.supported { | ||||||
|  | 		r.rawMode.ApplyMode() | ||||||
|  | 		defer r.normalMode.ApplyMode() | ||||||
|  | 		return r.State.PasswordPrompt(prompt) | ||||||
|  | 	} | ||||||
|  | 	if !r.warned { | ||||||
|  | 		fmt.Println("!! Unsupported terminal, password will be echoed.") | ||||||
|  | 		r.warned = true | ||||||
|  | 	} | ||||||
|  | 	// Just as in Prompt, handle printing the prompt here instead of relying on liner.
 | ||||||
|  | 	fmt.Print(prompt) | ||||||
|  | 	passwd, err = r.State.Prompt("") | ||||||
|  | 	fmt.Println() | ||||||
|  | 	return passwd, err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *userInputReader) ConfirmPrompt(prompt string) (bool, error) { | ||||||
|  | 	prompt = prompt + " [y/N] " | ||||||
|  | 	input, err := r.Prompt(prompt) | ||||||
|  | 	if len(input) > 0 && strings.ToUpper(input[:1]) == "Y" { | ||||||
|  | 		return true, nil | ||||||
|  | 	} | ||||||
|  | 	return false, err | ||||||
|  | } | ||||||
| @ -75,8 +75,9 @@ func (self *Jeth) UnlockAccount(call otto.FunctionCall) (response otto.Value) { | |||||||
| 	// if password is not given or as null value -> ask user for password
 | 	// if password is not given or as null value -> ask user for password
 | ||||||
| 	if call.Argument(1).IsUndefined() || call.Argument(1).IsNull() { | 	if call.Argument(1).IsUndefined() || call.Argument(1).IsNull() { | ||||||
| 		fmt.Printf("Unlock account %s\n", account) | 		fmt.Printf("Unlock account %s\n", account) | ||||||
| 		if password, err := PromptPassword("Passphrase: ", true); err == nil { | 		if input, err := Stdin.PasswordPrompt("Passphrase: "); err != nil { | ||||||
| 			passwd, _ = otto.ToValue(password) | 			return otto.FalseValue() | ||||||
|  | 			passwd, _ = otto.ToValue(input) | ||||||
| 		} else { | 		} else { | ||||||
| 			throwJSExeception(err.Error()) | 			throwJSExeception(err.Error()) | ||||||
| 		} | 		} | ||||||
| @ -111,11 +112,11 @@ func (self *Jeth) NewAccount(call otto.FunctionCall) (response otto.Value) { | |||||||
| 	var passwd string | 	var passwd string | ||||||
| 	if len(call.ArgumentList) == 0 { | 	if len(call.ArgumentList) == 0 { | ||||||
| 		var err error | 		var err error | ||||||
| 		passwd, err = PromptPassword("Passphrase: ", true) | 		passwd, err = Stdin.PasswordPrompt("Passphrase: ") | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return otto.FalseValue() | 			return otto.FalseValue() | ||||||
| 		} | 		} | ||||||
| 		passwd2, err := PromptPassword("Repeat passphrase: ", true) | 		passwd2, err := Stdin.PasswordPrompt("Repeat passphrase: ") | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return otto.FalseValue() | 			return otto.FalseValue() | ||||||
| 		} | 		} | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user