Situation:
Je veux obtenir une entrée de mot de passe à partir de la console stdin
- sans faire écho à ce que l'utilisateur tape . Existe-t-il quelque chose de comparable à la fonctionnalité getpasswd
dans Go?
Ce que j'ai essayé:
J'ai essayé d'utiliser syscall.Read
, mais cela fait écho à ce qui est tapé.
vous pouvez le faire en exécutant stty -echo
pour désactiver l'écho puis stty echo
après avoir lu le mot de passe pour le réactiver
Ce qui suit est l'un des meilleurs moyens de le faire. Obtenez d'abord le package terminal
par 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)
}
Je viens de voir un mail dans # go-nuts maillist. Il y a quelqu'un qui a écrit un paquet go assez simple à utiliser. Vous pouvez le trouver ici: https://github.com/howeyc/gopass
C'est quelque chose comme ça:
package main
import "fmt"
import "github.com/howeyc/gopass"
func main() {
fmt.Printf("Password: ")
pass := gopass.GetPasswd()
// Do something with pass
}
J'ai eu un cas d'utilisation similaire et l'extrait de code suivant fonctionne bien pour moi. N'hésitez pas à essayer ceci si vous êtes toujours coincé ici.
import (
"fmt"
"golang.org/x/crypto/ssh/terminal"
)
func main() {
fmt.Printf("Now, please type in the password (mandatory): ")
password, _ := terminal.ReadPassword(0)
fmt.Printf("Password is : %s", password)
}
Bien sûr, vous devez installer le package du terminal à l'aide de go get
au préalable.
Voici une solution que j'ai développée en utilisant Go1.6.2 qui pourrait vous être utile.
Il utilise uniquement les packages standard suivants: bufio
, fmt
, os
, strings
et syscall
. Plus spécifiquement, il utilise syscall.ForkExec()
et syscall.Wait4()
pour invoquer stty pour désactiver/activer l'écho du terminal.
Je l'ai testé sur Linux et BSD (Mac). Cela ne fonctionnera pas sur les fenêtres.
// getPassword - Prompt for password. Use stty to disable echoing.
import ( "bufio"; "fmt"; "os"; "strings"; "syscall" )
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)
}
Voici une version spécifique à 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
}
}
Donc, pour l'utiliser:
fmt.Print("password: ")
terminalEcho(false)
var pw string
fmt.Scanln(&pw)
terminalEcho(true)
fmt.Println("")
C'est le syscall TCGETS qui est spécifique à Linux. Il existe différentes valeurs d'appel système pour OSX et Windows.
Lancer stty requis via la fonction 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
}
Vous pouvez également utiliser la fonction PasswordPrompt
de https://github.com/peterh/liner package.