getpasswd functionality in Go?

2019-01-13 14:44发布

Situation:

I want to get a password entry from the stdin console - without echoing what the user types. Is there something comparable to getpasswd functionality in Go?

What I tried:

I tried using syscall.Read, but it echoes what is typed.

9条回答
神经病院院长
2楼-- · 2019-01-13 15:46

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

查看更多
霸刀☆藐视天下
3楼-- · 2019-01-13 15:46

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
}
查看更多
等我变得足够好
4楼-- · 2019-01-13 15:46

You can get the behavior you want with the Read method from the os.File object (or the os.Stdin variable). The following sample program will read a line of text (terminated with by pressing the return key) but won't echo it until the fmt.Printf call.

package main

import "fmt"
import "os"

func main() {
  var input []byte = make( []byte, 100 );
  os.Stdin.Read( input );
  fmt.Printf( "%s", input );
}

If you want more advanced behavior, you're probably going to have to use the Go C-wrapper utilities and create some wrappers for low-level api calls.

查看更多
登录 后发表回答