web-dev-qa-db-fra.com

Fonctionnalité getpasswd dans Go?

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é.

51
RogerV

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

7
jspcal

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)
}

http://play.golang.org/p/l-9IP1mrhA

74
gihanchanuka

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
}
27
Fatih Arslan

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.

5
rjni

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)
}
3
Joe Linoff

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.

2
Colin Fox

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
}
1
RogerV

Vous pouvez également utiliser la fonction PasswordPrompt de https://github.com/peterh/liner package.

1
hagh