//go:build windows // +build windows // Note the terminal manipulation functions herein are mostly stubs. They // don't really do anything and the xs demo client depends on a wrapper // script using the 'stty' tool to actually set the proper mode for // password login and raw mode required, then restoring it upon logout/exit. // // mintty uses named pipes and ptys rather than Windows 'console' // mode, and Go's x/crypto/ssh/terminal libs only work for the latter, so // until some truly cross-platform terminal mode handling makes it into the // go std lib I'm not going to jump through hoops trying to be cross-platform // here; the wrapper does the bare minimum to make the client workable // under MSYS+mintty which is what I use. package xs import ( "bufio" "fmt" "log" "os" "os/exec" "os/signal" ) type State struct { } // MakeRaw put the terminal connected to the given file descriptor into raw // mode and returns the previous state of the terminal so that it can be // restored. func MakeRaw(f *os.File) (*State, error) { cmd := exec.Command("stty", "-echo", "raw") cmd.Stdin = f err := cmd.Run() if err != nil { log.Fatal(err) return &State{}, err } // MSYS2/CYGWIN: wintty needs CTRL-C caught // ---------------------------------------- c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, os.Kill) go func() { for sig := range c { _ = sig //fmt.Println(sig) } }() // ---------------------------------------- return &State{}, nil } // GetState returns the current state of a terminal which may be useful to // restore the terminal after a signal. func GetState(f *os.File) (*State, error) { return &State{}, nil } // Restore restores the terminal connected to the given file descriptor to a // previous state. func Restore(f *os.File, state *State) error { cmd := exec.Command("stty", "sane") cmd.Stdin = f err := cmd.Run() if err != nil { log.Fatal(err) return nil } return nil } // ReadPassword reads a line of input from a terminal without local echo. This // is commonly used for inputting passwords and other sensitive data. The slice // returned does not include the \n. func ReadPassword(f *os.File) (pw []byte, err error) { sttycmd, err := exec.LookPath("stty") if err != nil { return nil, err } else { //fmt.Printf("stty found at: %v\n", sttycmd) cmdOff := exec.Command(sttycmd, "-echo") cmdOff.Stdin = f //os.Stdin cmdOff.Stdout = nil //os.Stdout cmdOff.Stderr = nil //os.Stderr err = cmdOff.Run() if err != nil { return nil, err } //fmt.Printf("Enter password:") scanner := bufio.NewScanner(os.Stdin) scanner.Scan() err = scanner.Err() if err != nil { return nil, err } pw = scanner.Bytes() fmt.Println() cmdOn := exec.Command(sttycmd, "echo") cmdOn.Stdin = f //os.Stdin cmdOn.Stdout = nil //os.Stdout cmdOn.Stderr = nil //os.Stderr err = cmdOn.Run() if err != nil { return nil, err } } return }