getpasswd functionality in Go?

前端 未结 9 1658
春和景丽
春和景丽 2020-12-02 13:08

Situation:

I want to get a password entry from the stdin console - without echoing what the user types. Is there something com

相关标签:
9条回答
  • 2020-12-02 13:21

    The following is one of best ways to get it done. First get terminal package by 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, error) {
        reader := bufio.NewReader(os.Stdin)
    
        fmt.Print("Enter Username: ")
        username, err := reader.ReadString('\n')
        if err != nil {
            return "", "", err
        }
    
        fmt.Print("Enter Password: ")
        bytePassword, err := terminal.ReadPassword(int(syscall.Stdin))
        if err != nil {
            return "", "", err
        }
    
        password := string(bytePassword)
        return strings.TrimSpace(username), strings.TrimSpace(password), nil
    }
    

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

    0 讨论(0)
  • 2020-12-02 13:21

    You could also use PasswordPrompt function of https://github.com/peterh/liner package.

    0 讨论(0)
  • 2020-12-02 13:32

    Here is a version specific to 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
        }
    }
    

    So to use it:

    fmt.Print("password: ")
    
    terminalEcho(false)
    var pw string
    fmt.Scanln(&pw)
    terminalEcho(true)
    fmt.Println("")
    

    It's the TCGETS syscall that is linux specific. There are different syscall values for OSX and Windows.

    0 讨论(0)
  • 2020-12-02 13:33

    Required launching stty via Go ForkExec() function:

    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
    }
    
    0 讨论(0)
  • 2020-12-02 13:34

    Just saw a mail in #go-nuts maillist. There is someone who wrote quite a simple go package to be used. You can find it here: https://github.com/howeyc/gopass

    It something like that:

    package main
    
    import "fmt"
    import "github.com/howeyc/gopass"
    
    func main() {
        fmt.Printf("Password: ")
        pass := gopass.GetPasswd()
        // Do something with pass
    }
    
    0 讨论(0)
  • 2020-12-02 13:36

    Here is a solution that I developed using Go1.6.2 that you might find useful.

    It only uses the following standard packages: bufio, fmt, os, strings and syscall. More specifically, it uses syscall.ForkExec() and syscall.Wait4() to invoke stty to disable/enable terminal echo.

    I have tested it on Linux and BSD (Mac). It will not work on windows.

    // 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)
    }
    
    0 讨论(0)
提交回复
热议问题