mirror of https://gogs.blitter.com/RLabs/xs
114 lines
2.9 KiB
Go
114 lines
2.9 KiB
Go
//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
|
|
}
|