Ответ 1
вы можете сделать это, выполнив stty -echo
, чтобы отключить эхо-сигнал, а затем stty echo
после прочтения пароля, чтобы вернуть его обратно на
Хотелось бы иметь возможность вводить пароль из консоли stdin, но, конечно, не повторяя то, что пользователь вводит.
Есть ли что-то сопоставимое с функциями getpasswd в Go? (Язык Google Go)
Я попробовал использовать syscall.Read, но он перекликается с тем, что напечатано.
вы можете сделать это, выполнив stty -echo
, чтобы отключить эхо-сигнал, а затем stty echo
после прочтения пароля, чтобы вернуть его обратно на
Ниже приведен один из лучших способов, чтобы сделать это.
Сначала получите пакет terminal
go get golang.org/x/crypto/ssh
package main
import (
"bufio"
"fmt"
"os"
"strings"
"syscall"
"golang.org/x/crypto/ssh/terminal"
)
func main() {
username, password := credentials()
fmt.Printf("Username: %s, Password: %s\n", username, password)
}
func credentials() (string, string) {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter Username: ")
username, _ := reader.ReadString('\n')
fmt.Print("Enter Password: ")
bytePassword, err := terminal.ReadPassword(int(syscall.Stdin))
if err == nil {
fmt.Println("\nPassword typed: " + string(bytePassword))
}
password := string(bytePassword)
return strings.TrimSpace(username), strings.TrimSpace(password)
}
Только что увидел почту в # go-nuts maillist. Есть кто-то, кто написал довольно простой пакет для использования. Вы можете найти его здесь: https://github.com/howeyc/gopass
Это что-то вроде этого:
package main
import "fmt"
import "github.com/howeyc/gopass"
func main() {
fmt.Printf("Password: ")
pass := gopass.GetPasswd()
// Do something with pass
}
Вот версия, специфичная для Linux:
func terminalEcho(show bool) {
// Enable or disable echoing terminal input. This is useful specifically for
// when users enter passwords.
// calling terminalEcho(true) turns on echoing (normal mode)
// calling terminalEcho(false) hides terminal input.
var termios = &syscall.Termios{}
var fd = os.Stdout.Fd()
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd,
syscall.TCGETS, uintptr(unsafe.Pointer(termios))); err != 0 {
return
}
if show {
termios.Lflag |= syscall.ECHO
} else {
termios.Lflag &^= syscall.ECHO
}
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd,
uintptr(syscall.TCSETS),
uintptr(unsafe.Pointer(termios))); err != 0 {
return
}
}
Итак, чтобы использовать его:
fmt.Print("password: ")
terminalEcho(false)
var pw string
fmt.Scanln(&pw)
terminalEcho(true)
fmt.Println("")
Это системный вызов TCGETS, специфичный для Linux. Существуют разные значения syscall для OSX и Windows.
Вы также можете использовать функцию PasswordPrompt
https://github.com/peterh/liner.
Вот решение, которое я разработал с помощью Go1.6.2, которое может вам пригодиться.
Он использует только следующие стандартные пакеты: bufio, fmt, reader, string и syscall. Более конкретно, он использует syscall.ForkExec()
и syscall.Wait4()
для вызова stty для отключения/включения терминального эха.
Я тестировал его на Linux и BSD (Mac). Он не будет работать на окнах.
// getPassword - Prompt for password. Use stty to disable echoing.
func getPassword(prompt string) string {
fmt.Print(prompt)
// Common settings and variables for both stty calls.
attrs := syscall.ProcAttr{
Dir: "",
Env: []string{},
Files: []uintptr{os.Stdin.Fd(), os.Stdout.Fd(), os.Stderr.Fd()},
Sys: nil}
var ws syscall.WaitStatus
// Disable echoing.
pid, err := syscall.ForkExec(
"/bin/stty",
[]string{"stty", "-echo"},
&attrs)
if err != nil {
panic(err)
}
// Wait for the stty process to complete.
_, err = syscall.Wait4(pid, &ws, 0, nil)
if err != nil {
panic(err)
}
// Echo is disabled, now grab the data.
reader := bufio.NewReader(os.Stdin)
text, err := reader.ReadString('\n')
if err != nil {
panic(err)
}
// Re-enable echo.
pid, err = syscall.ForkExec(
"/bin/stty",
[]string{"stty", "echo"},
&attrs)
if err != nil {
panic(err)
}
// Wait for the stty process to complete.
_, err = syscall.Wait4(pid, &ws, 0, nil)
if err != nil {
panic(err)
}
return strings.TrimSpace(text)
}
Требуется запуск stty через функцию Go ForkExec():
package main
import (
os "os"
bufio "bufio"
fmt "fmt"
str "strings"
)
func main() {
fmt.Println();
if passwd, err := Getpasswd("Enter password: "); err == nil {
fmt.Printf("\n\nPassword: '%s'\n",passwd)
}
}
func Getpasswd(prompt string) (passwd string, err os.Error) {
fmt.Print(prompt);
const stty_arg0 = "/bin/stty";
stty_argv_e_off := []string{"stty","-echo"};
stty_argv_e_on := []string{"stty","echo"};
const exec_cwdir = "";
fd := []*os.File{os.Stdin,os.Stdout,os.Stderr};
pid, err := os.ForkExec(stty_arg0,stty_argv_e_off,nil,exec_cwdir,fd);
if err != nil {
return passwd, os.NewError(fmt.Sprintf("Failed turning off console echo for password entry:\n\t%s",err))
}
rd := bufio.NewReader(os.Stdin);
os.Wait(pid,0);
line, err := rd.ReadString('\n');
if err == nil {
passwd = str.TrimSpace(line)
} else {
err = os.NewError(fmt.Sprintf("Failed during password entry: %s",err))
}
pid, e := os.ForkExec(stty_arg0,stty_argv_e_on,nil,exec_cwdir,fd);
if e == nil {
os.Wait(pid,0)
} else if err == nil {
err = os.NewError(fmt.Sprintf("Failed turning on console echo post password entry:\n\t%s",e))
}
return passwd, err
}
Вы можете получить нужное поведение с помощью метода Read из объекта os.File(или переменной os.Stdin). Следующая примерная программа будет читать строку текста (завершается нажатием клавиши возврата), но не будет повторять ее до вызова fmt.Printf.
package main
import "fmt"
import "os"
func main() {
var input []byte = make( []byte, 100 );
os.Stdin.Read( input );
fmt.Printf( "%s", input );
}
Если вам требуется более продвинутое поведение, вам, вероятно, придется использовать утилиты Go C-wrapper и создать некоторые оболочки для низкоуровневых вызовов api.