summaryrefslogtreecommitdiffstats
path: root/vendor/golang.org/x/crypto/ssh/terminal
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/crypto/ssh/terminal')
-rw-r--r--vendor/golang.org/x/crypto/ssh/terminal/terminal.go73
-rw-r--r--vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go59
-rw-r--r--vendor/golang.org/x/crypto/ssh/terminal/util.go38
-rw-r--r--vendor/golang.org/x/crypto/ssh/terminal/util_windows.go35
4 files changed, 145 insertions, 60 deletions
diff --git a/vendor/golang.org/x/crypto/ssh/terminal/terminal.go b/vendor/golang.org/x/crypto/ssh/terminal/terminal.go
index 741eeb13f..18379a935 100644
--- a/vendor/golang.org/x/crypto/ssh/terminal/terminal.go
+++ b/vendor/golang.org/x/crypto/ssh/terminal/terminal.go
@@ -132,8 +132,11 @@ const (
keyPasteEnd
)
-var pasteStart = []byte{keyEscape, '[', '2', '0', '0', '~'}
-var pasteEnd = []byte{keyEscape, '[', '2', '0', '1', '~'}
+var (
+ crlf = []byte{'\r', '\n'}
+ pasteStart = []byte{keyEscape, '[', '2', '0', '0', '~'}
+ pasteEnd = []byte{keyEscape, '[', '2', '0', '1', '~'}
+)
// bytesToKey tries to parse a key sequence from b. If successful, it returns
// the key and the remainder of the input. Otherwise it returns utf8.RuneError.
@@ -333,7 +336,7 @@ func (t *Terminal) advanceCursor(places int) {
// So, if we are stopping at the end of a line, we
// need to write a newline so that our cursor can be
// advanced to the next line.
- t.outBuf = append(t.outBuf, '\n')
+ t.outBuf = append(t.outBuf, '\r', '\n')
}
}
@@ -593,6 +596,35 @@ func (t *Terminal) writeLine(line []rune) {
}
}
+// writeWithCRLF writes buf to w but replaces all occurrences of \n with \r\n.
+func writeWithCRLF(w io.Writer, buf []byte) (n int, err error) {
+ for len(buf) > 0 {
+ i := bytes.IndexByte(buf, '\n')
+ todo := len(buf)
+ if i >= 0 {
+ todo = i
+ }
+
+ var nn int
+ nn, err = w.Write(buf[:todo])
+ n += nn
+ if err != nil {
+ return n, err
+ }
+ buf = buf[todo:]
+
+ if i >= 0 {
+ if _, err = w.Write(crlf); err != nil {
+ return n, err
+ }
+ n += 1
+ buf = buf[1:]
+ }
+ }
+
+ return n, nil
+}
+
func (t *Terminal) Write(buf []byte) (n int, err error) {
t.lock.Lock()
defer t.lock.Unlock()
@@ -600,7 +632,7 @@ func (t *Terminal) Write(buf []byte) (n int, err error) {
if t.cursorX == 0 && t.cursorY == 0 {
// This is the easy case: there's nothing on the screen that we
// have to move out of the way.
- return t.c.Write(buf)
+ return writeWithCRLF(t.c, buf)
}
// We have a prompt and possibly user input on the screen. We
@@ -620,7 +652,7 @@ func (t *Terminal) Write(buf []byte) (n int, err error) {
}
t.outBuf = t.outBuf[:0]
- if n, err = t.c.Write(buf); err != nil {
+ if n, err = writeWithCRLF(t.c, buf); err != nil {
return
}
@@ -740,8 +772,6 @@ func (t *Terminal) readLine() (line string, err error) {
t.remainder = t.inBuf[:n+len(t.remainder)]
}
-
- panic("unreachable") // for Go 1.0.
}
// SetPrompt sets the prompt to be used when reading subsequent lines.
@@ -890,3 +920,32 @@ func (s *stRingBuffer) NthPreviousEntry(n int) (value string, ok bool) {
}
return s.entries[index], true
}
+
+// readPasswordLine reads from reader until it finds \n or io.EOF.
+// The slice returned does not include the \n.
+// readPasswordLine also ignores any \r it finds.
+func readPasswordLine(reader io.Reader) ([]byte, error) {
+ var buf [1]byte
+ var ret []byte
+
+ for {
+ n, err := reader.Read(buf[:])
+ if n > 0 {
+ switch buf[0] {
+ case '\n':
+ return ret, nil
+ case '\r':
+ // remove \r from passwords on Windows
+ default:
+ ret = append(ret, buf[0])
+ }
+ continue
+ }
+ if err != nil {
+ if err == io.EOF && len(ret) > 0 {
+ return ret, nil
+ }
+ return ret, err
+ }
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go b/vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go
index 6bdefb4ec..901c72ab3 100644
--- a/vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go
+++ b/vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go
@@ -5,6 +5,7 @@
package terminal
import (
+ "bytes"
"io"
"os"
"testing"
@@ -269,6 +270,50 @@ func TestTerminalSetSize(t *testing.T) {
}
}
+func TestReadPasswordLineEnd(t *testing.T) {
+ var tests = []struct {
+ input string
+ want string
+ }{
+ {"\n", ""},
+ {"\r\n", ""},
+ {"test\r\n", "test"},
+ {"testtesttesttes\n", "testtesttesttes"},
+ {"testtesttesttes\r\n", "testtesttesttes"},
+ {"testtesttesttesttest\n", "testtesttesttesttest"},
+ {"testtesttesttesttest\r\n", "testtesttesttesttest"},
+ }
+ for _, test := range tests {
+ buf := new(bytes.Buffer)
+ if _, err := buf.WriteString(test.input); err != nil {
+ t.Fatal(err)
+ }
+
+ have, err := readPasswordLine(buf)
+ if err != nil {
+ t.Errorf("readPasswordLine(%q) failed: %v", test.input, err)
+ continue
+ }
+ if string(have) != test.want {
+ t.Errorf("readPasswordLine(%q) returns %q, but %q is expected", test.input, string(have), test.want)
+ continue
+ }
+
+ if _, err = buf.WriteString(test.input); err != nil {
+ t.Fatal(err)
+ }
+ have, err = readPasswordLine(buf)
+ if err != nil {
+ t.Errorf("readPasswordLine(%q) failed: %v", test.input, err)
+ continue
+ }
+ if string(have) != test.want {
+ t.Errorf("readPasswordLine(%q) returns %q, but %q is expected", test.input, string(have), test.want)
+ continue
+ }
+ }
+}
+
func TestMakeRawState(t *testing.T) {
fd := int(os.Stdout.Fd())
if !IsTerminal(fd) {
@@ -289,3 +334,17 @@ func TestMakeRawState(t *testing.T) {
t.Errorf("states do not match; was %v, expected %v", raw, st)
}
}
+
+func TestOutputNewlines(t *testing.T) {
+ // \n should be changed to \r\n in terminal output.
+ buf := new(bytes.Buffer)
+ term := NewTerminal(buf, ">")
+
+ term.Write([]byte("1\n2\n"))
+ output := string(buf.Bytes())
+ const expected = "1\r\n2\r\n"
+
+ if output != expected {
+ t.Errorf("incorrect output: was %q, expected %q", output, expected)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util.go b/vendor/golang.org/x/crypto/ssh/terminal/util.go
index c869213ec..d01919614 100644
--- a/vendor/golang.org/x/crypto/ssh/terminal/util.go
+++ b/vendor/golang.org/x/crypto/ssh/terminal/util.go
@@ -17,7 +17,6 @@
package terminal // import "golang.org/x/crypto/ssh/terminal"
import (
- "io"
"syscall"
"unsafe"
)
@@ -72,8 +71,10 @@ func GetState(fd int) (*State, error) {
// Restore restores the terminal connected to the given file descriptor to a
// previous state.
func Restore(fd int, state *State) error {
- _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0)
- return err
+ if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0); err != 0 {
+ return err
+ }
+ return nil
}
// GetSize returns the dimensions of the given terminal.
@@ -86,6 +87,13 @@ func GetSize(fd int) (width, height int, err error) {
return int(dimensions[1]), int(dimensions[0]), nil
}
+// passwordReader is an io.Reader that reads from a specific file descriptor.
+type passwordReader int
+
+func (r passwordReader) Read(buf []byte) (int, error) {
+ return syscall.Read(int(r), buf)
+}
+
// 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.
@@ -107,27 +115,5 @@ func ReadPassword(fd int) ([]byte, error) {
syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0)
}()
- var buf [16]byte
- var ret []byte
- for {
- n, err := syscall.Read(fd, buf[:])
- if err != nil {
- return nil, err
- }
- if n == 0 {
- if len(ret) == 0 {
- return nil, io.EOF
- }
- break
- }
- if buf[n-1] == '\n' {
- n--
- }
- ret = append(ret, buf[:n]...)
- if n < len(buf) {
- break
- }
- }
-
- return ret, nil
+ return readPasswordLine(passwordReader(fd))
}
diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go b/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go
index ae9fa9ec1..e0a1f36ce 100644
--- a/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go
+++ b/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go
@@ -17,7 +17,6 @@
package terminal
import (
- "io"
"syscall"
"unsafe"
)
@@ -123,6 +122,13 @@ func GetSize(fd int) (width, height int, err error) {
return int(info.size.x), int(info.size.y), nil
}
+// passwordReader is an io.Reader that reads from a specific Windows HANDLE.
+type passwordReader int
+
+func (r passwordReader) Read(buf []byte) (int, error) {
+ return syscall.Read(syscall.Handle(r), buf)
+}
+
// 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.
@@ -145,30 +151,5 @@ func ReadPassword(fd int) ([]byte, error) {
syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(old), 0)
}()
- var buf [16]byte
- var ret []byte
- for {
- n, err := syscall.Read(syscall.Handle(fd), buf[:])
- if err != nil {
- return nil, err
- }
- if n == 0 {
- if len(ret) == 0 {
- return nil, io.EOF
- }
- break
- }
- if buf[n-1] == '\n' {
- n--
- }
- if n > 0 && buf[n-1] == '\r' {
- n--
- }
- ret = append(ret, buf[:n]...)
- if n < len(buf) {
- break
- }
- }
-
- return ret, nil
+ return readPasswordLine(passwordReader(fd))
}