зеркало из https://github.com/mislav/hub.git
Merge branch 'update-gopass'
This commit is contained in:
Коммит
33bd0d04f7
|
@ -148,7 +148,8 @@ func (c *Config) PromptForPassword(host, user string) (pass string) {
|
|||
|
||||
ui.Printf("%s password for %s (never stored): ", host, user)
|
||||
if ui.IsTerminal(os.Stdout) {
|
||||
pass = string(gopass.GetPasswd())
|
||||
passBytes, _ := gopass.GetPasswd()
|
||||
pass = string(passBytes)
|
||||
} else {
|
||||
pass = c.scanLine()
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
ISC License
|
||||
|
||||
Copyright (c) 2012 Chris Howey
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# getpasswd in Go
|
||||
# getpasswd in Go [![GoDoc](https://godoc.org/github.com/howeyc/gopass?status.svg)](https://godoc.org/github.com/howeyc/gopass) [![Build Status](https://secure.travis-ci.org/howeyc/gopass.png?branch=master)](http://travis-ci.org/howeyc/gopass)
|
||||
|
||||
Retrieve password from user terminal input without echo
|
||||
Retrieve password from user terminal or piped input without echo.
|
||||
|
||||
Verified on BSD, Linux, and Windows.
|
||||
|
||||
|
@ -13,8 +13,14 @@ import "github.com/howeyc/gopass"
|
|||
|
||||
func main() {
|
||||
fmt.Printf("Password: ")
|
||||
pass := gopass.GetPasswd() // Silent, for *'s use gopass.GetPasswdMasked()
|
||||
// Do something with pass
|
||||
|
||||
// Silent. For printing *'s use gopass.GetPasswdMasked()
|
||||
pass, err := gopass.GetPasswd()
|
||||
if err != nil {
|
||||
// Handle gopass.ErrInterrupted or getch() read error
|
||||
}
|
||||
|
||||
// Do something with pass
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
// +build freebsd openbsd netbsd
|
||||
|
||||
package gopass
|
||||
|
||||
/*
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int getch() {
|
||||
int ch;
|
||||
struct termios t_old, t_new;
|
||||
|
||||
tcgetattr(STDIN_FILENO, &t_old);
|
||||
t_new = t_old;
|
||||
t_new.c_lflag &= ~(ICANON | ECHO);
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &t_new);
|
||||
|
||||
ch = getchar();
|
||||
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &t_old);
|
||||
return ch;
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func getch() byte {
|
||||
return byte(C.getch())
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
// +build linux darwin
|
||||
|
||||
package gopass
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
func getch() byte {
|
||||
if oldState, err := terminal.MakeRaw(0); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
defer terminal.Restore(0, oldState)
|
||||
}
|
||||
|
||||
var buf [1]byte
|
||||
if n, err := syscall.Read(0, buf[:]); n == 0 || err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return buf[0]
|
||||
}
|
|
@ -1,44 +1,93 @@
|
|||
package gopass
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
var defaultGetCh = func() (byte, error) {
|
||||
buf := make([]byte, 1)
|
||||
if n, err := os.Stdin.Read(buf); n == 0 || err != nil {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return 0, io.EOF
|
||||
}
|
||||
return buf[0], nil
|
||||
}
|
||||
|
||||
var (
|
||||
maxLength = 512
|
||||
ErrInterrupted = errors.New("interrupted")
|
||||
ErrMaxLengthExceeded = fmt.Errorf("maximum byte limit (%v) exceeded", maxLength)
|
||||
|
||||
// Provide variable so that tests can provide a mock implementation.
|
||||
getch = defaultGetCh
|
||||
)
|
||||
|
||||
// getPasswd returns the input read from terminal.
|
||||
// If masked is true, typing will be matched by asterisks on the screen.
|
||||
// Otherwise, typing will echo nothing.
|
||||
func getPasswd(masked bool) []byte {
|
||||
func getPasswd(masked bool) ([]byte, error) {
|
||||
var err error
|
||||
var pass, bs, mask []byte
|
||||
if masked {
|
||||
bs = []byte("\b \b")
|
||||
mask = []byte("*")
|
||||
}
|
||||
|
||||
for {
|
||||
if v := getch(); v == 127 || v == 8 {
|
||||
if terminal.IsTerminal(int(os.Stdin.Fd())) {
|
||||
if oldState, err := terminal.MakeRaw(int(os.Stdin.Fd())); err != nil {
|
||||
return pass, err
|
||||
} else {
|
||||
defer terminal.Restore(int(os.Stdin.Fd()), oldState)
|
||||
}
|
||||
}
|
||||
|
||||
// Track total bytes read, not just bytes in the password. This ensures any
|
||||
// errors that might flood the console with nil or -1 bytes infinitely are
|
||||
// capped.
|
||||
var counter int
|
||||
for counter = 0; counter <= maxLength; counter++ {
|
||||
if v, e := getch(); e != nil {
|
||||
err = e
|
||||
break
|
||||
} else if v == 127 || v == 8 {
|
||||
if l := len(pass); l > 0 {
|
||||
pass = pass[:l-1]
|
||||
os.Stdout.Write(bs)
|
||||
fmt.Print(string(bs))
|
||||
}
|
||||
} else if v == 13 || v == 10 {
|
||||
break
|
||||
} else if v == 3 {
|
||||
err = ErrInterrupted
|
||||
break
|
||||
} else if v != 0 {
|
||||
pass = append(pass, v)
|
||||
os.Stdout.Write(mask)
|
||||
fmt.Print(string(mask))
|
||||
}
|
||||
}
|
||||
println()
|
||||
return pass
|
||||
|
||||
if counter > maxLength {
|
||||
err = ErrMaxLengthExceeded
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
return pass, err
|
||||
}
|
||||
|
||||
// GetPasswd returns the password read from the terminal without echoing input.
|
||||
// The returned byte array does not include end-of-line characters.
|
||||
func GetPasswd() []byte {
|
||||
func GetPasswd() ([]byte, error) {
|
||||
return getPasswd(false)
|
||||
}
|
||||
|
||||
// GetPasswdMasked returns the password read from the terminal, echoing asterisks.
|
||||
// The returned byte array does not include end-of-line characters.
|
||||
func GetPasswdMasked() []byte {
|
||||
func GetPasswdMasked() ([]byte, error) {
|
||||
return getPasswd(true)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,228 @@
|
|||
package gopass
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TestGetPasswd tests the password creation and output based on a byte buffer
|
||||
// as input to mock the underlying getch() methods.
|
||||
func TestGetPasswd(t *testing.T) {
|
||||
type testData struct {
|
||||
input []byte
|
||||
|
||||
// Due to how backspaces are written, it is easier to manually write
|
||||
// each expected output for the masked cases.
|
||||
masked string
|
||||
password string
|
||||
byesLeft int
|
||||
reason string
|
||||
}
|
||||
|
||||
ds := []testData{
|
||||
testData{[]byte("abc\n"), "***\n", "abc", 0, "Password parsing should stop at \\n"},
|
||||
testData{[]byte("abc\r"), "***\n", "abc", 0, "Password parsing should stop at \\r"},
|
||||
testData{[]byte("a\nbc\n"), "*\n", "a", 3, "Password parsing should stop at \\n"},
|
||||
testData{[]byte("*!]|\n"), "****\n", "*!]|", 0, "Special characters shouldn't affect the password."},
|
||||
|
||||
testData{[]byte("abc\r\n"), "***\n", "abc", 1,
|
||||
"Password parsing should stop at \\r; Windows LINE_MODE should be unset so \\r is not converted to \\r\\n."},
|
||||
|
||||
testData{[]byte{'a', 'b', 'c', 8, '\n'}, "***\b \b\n", "ab", 0, "Backspace byte should remove the last read byte."},
|
||||
testData{[]byte{'a', 'b', 127, 'c', '\n'}, "**\b \b*\n", "ac", 0, "Delete byte should remove the last read byte."},
|
||||
testData{[]byte{'a', 'b', 127, 'c', 8, 127, '\n'}, "**\b \b*\b \b\b \b\n", "", 0, "Successive deletes continue to delete."},
|
||||
testData{[]byte{8, 8, 8, '\n'}, "\n", "", 0, "Deletes before characters are noops."},
|
||||
testData{[]byte{8, 8, 8, 'a', 'b', 'c', '\n'}, "***\n", "abc", 0, "Deletes before characters are noops."},
|
||||
|
||||
testData{[]byte{'a', 'b', 0, 'c', '\n'}, "***\n", "abc", 0,
|
||||
"Nil byte should be ignored due; may get unintended nil bytes from syscalls on Windows."},
|
||||
}
|
||||
|
||||
// Redirecting output for tests as they print to os.Stdout but we want to
|
||||
// capture and test the output.
|
||||
origStdOut := os.Stdout
|
||||
for _, masked := range []bool{true, false} {
|
||||
for _, d := range ds {
|
||||
pipeBytesToStdin(d.input)
|
||||
|
||||
r, w, err := os.Pipe()
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
os.Stdout = w
|
||||
|
||||
result, err := getPasswd(masked)
|
||||
os.Stdout = origStdOut
|
||||
if err != nil {
|
||||
t.Errorf("Error getting password:", err.Error())
|
||||
}
|
||||
leftOnBuffer := flushStdin()
|
||||
|
||||
// Test output (masked and unmasked). Delete/backspace actually
|
||||
// deletes, overwrites and deletes again. As a result, we need to
|
||||
// remove those from the pipe afterwards to mimic the console's
|
||||
// interpretation of those bytes.
|
||||
w.Close()
|
||||
output, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
var expectedOutput []byte
|
||||
if masked {
|
||||
expectedOutput = []byte(d.masked)
|
||||
} else {
|
||||
expectedOutput = []byte("\n")
|
||||
}
|
||||
if bytes.Compare(expectedOutput, output) != 0 {
|
||||
t.Errorf("Expected output to equal %v (%q) but got %v (%q) instead when masked=%v. %s", expectedOutput, string(expectedOutput), output, string(output), masked, d.reason)
|
||||
}
|
||||
|
||||
if string(result) != d.password {
|
||||
t.Errorf("Expected %q but got %q instead when masked=%v. %s", d.password, result, masked, d.reason)
|
||||
}
|
||||
|
||||
if leftOnBuffer != d.byesLeft {
|
||||
t.Errorf("Expected %v bytes left on buffer but instead got %v when masked=%v. %s", d.byesLeft, leftOnBuffer, masked, d.reason)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestPipe ensures we get our expected pipe behavior.
|
||||
func TestPipe(t *testing.T) {
|
||||
type testData struct {
|
||||
input string
|
||||
password string
|
||||
expError error
|
||||
}
|
||||
ds := []testData{
|
||||
testData{"abc", "abc", io.EOF},
|
||||
testData{"abc\n", "abc", nil},
|
||||
testData{"abc\r", "abc", nil},
|
||||
testData{"abc\r\n", "abc", nil},
|
||||
}
|
||||
|
||||
for _, d := range ds {
|
||||
_, err := pipeToStdin(d.input)
|
||||
if err != nil {
|
||||
t.Log("Error writing input to stdin:", err)
|
||||
t.FailNow()
|
||||
}
|
||||
pass, err := GetPasswd()
|
||||
if string(pass) != d.password {
|
||||
t.Errorf("Expected %q but got %q instead.", d.password, string(pass))
|
||||
}
|
||||
if err != d.expError {
|
||||
t.Errorf("Expected %v but got %q instead.", d.expError, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// flushStdin reads from stdin for .5 seconds to ensure no bytes are left on
|
||||
// the buffer. Returns the number of bytes read.
|
||||
func flushStdin() int {
|
||||
ch := make(chan byte)
|
||||
go func(ch chan byte) {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
for {
|
||||
b, err := reader.ReadByte()
|
||||
if err != nil { // Maybe log non io.EOF errors, if you want
|
||||
close(ch)
|
||||
return
|
||||
}
|
||||
ch <- b
|
||||
}
|
||||
close(ch)
|
||||
}(ch)
|
||||
|
||||
numBytes := 0
|
||||
for {
|
||||
select {
|
||||
case _, ok := <-ch:
|
||||
if !ok {
|
||||
return numBytes
|
||||
}
|
||||
numBytes++
|
||||
case <-time.After(500 * time.Millisecond):
|
||||
return numBytes
|
||||
}
|
||||
}
|
||||
return numBytes
|
||||
}
|
||||
|
||||
// pipeToStdin pipes the given string onto os.Stdin by replacing it with an
|
||||
// os.Pipe. The write end of the pipe is closed so that EOF is read after the
|
||||
// final byte.
|
||||
func pipeToStdin(s string) (int, error) {
|
||||
pipeReader, pipeWriter, err := os.Pipe()
|
||||
if err != nil {
|
||||
fmt.Println("Error getting os pipes:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Stdin = pipeReader
|
||||
w, err := pipeWriter.WriteString(s)
|
||||
pipeWriter.Close()
|
||||
return w, err
|
||||
}
|
||||
|
||||
func pipeBytesToStdin(b []byte) (int, error) {
|
||||
return pipeToStdin(string(b))
|
||||
}
|
||||
|
||||
// TestGetPasswd_Err tests errors are properly handled from getch()
|
||||
func TestGetPasswd_Err(t *testing.T) {
|
||||
var inBuffer *bytes.Buffer
|
||||
getch = func() (byte, error) {
|
||||
b, err := inBuffer.ReadByte()
|
||||
if err != nil {
|
||||
return 13, err
|
||||
}
|
||||
if b == 'z' {
|
||||
return 'z', fmt.Errorf("Forced error; byte returned should not be considered accurate.")
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
defer func() { getch = defaultGetCh }()
|
||||
|
||||
for input, expectedPassword := range map[string]string{"abc": "abc", "abzc": "ab"} {
|
||||
inBuffer = bytes.NewBufferString(input)
|
||||
p, err := GetPasswdMasked()
|
||||
if string(p) != expectedPassword {
|
||||
t.Errorf("Expected %q but got %q instead.", expectedPassword, p)
|
||||
}
|
||||
if err == nil {
|
||||
t.Errorf("Expected error to be returned.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaxPasswordLength(t *testing.T) {
|
||||
type testData struct {
|
||||
input []byte
|
||||
expectedErr error
|
||||
|
||||
// Helper field to output in case of failure; rather than hundreds of
|
||||
// bytes.
|
||||
inputDesc string
|
||||
}
|
||||
|
||||
ds := []testData{
|
||||
testData{append(bytes.Repeat([]byte{'a'}, maxLength), '\n'), nil, fmt.Sprintf("%v 'a' bytes followed by a newline", maxLength)},
|
||||
testData{append(bytes.Repeat([]byte{'a'}, maxLength+1), '\n'), ErrMaxLengthExceeded, fmt.Sprintf("%v 'a' bytes followed by a newline", maxLength+1)},
|
||||
testData{append(bytes.Repeat([]byte{0x00}, maxLength+1), '\n'), ErrMaxLengthExceeded, fmt.Sprintf("%v 0x00 bytes followed by a newline", maxLength+1)},
|
||||
}
|
||||
|
||||
for _, d := range ds {
|
||||
pipeBytesToStdin(d.input)
|
||||
_, err := GetPasswd()
|
||||
if err != d.expectedErr {
|
||||
t.Errorf("Expected error to be %v; isntead got %v from %v", d.expectedErr, err, d.inputDesc)
|
||||
}
|
||||
}
|
||||
}
|
4
vendor/github.com/howeyc/gopass/vendor/golang.org/x/crypto/ssh/terminal/terminal.go
сгенерированный
поставляемый
4
vendor/github.com/howeyc/gopass/vendor/golang.org/x/crypto/ssh/terminal/terminal.go
сгенерированный
поставляемый
|
@ -789,6 +789,10 @@ func (t *Terminal) SetSize(width, height int) error {
|
|||
// If the width didn't change then nothing else needs to be
|
||||
// done.
|
||||
return nil
|
||||
case len(t.line) == 0 && t.cursorX == 0 && t.cursorY == 0:
|
||||
// If there is nothing on current line and no prompt printed,
|
||||
// just do nothing
|
||||
return nil
|
||||
case width < oldWidth:
|
||||
// Some terminals (e.g. xterm) will truncate lines that were
|
||||
// too long when shinking. Others, (e.g. gnome-terminal) will
|
||||
|
|
48
vendor/github.com/howeyc/gopass/vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go
сгенерированный
поставляемый
48
vendor/github.com/howeyc/gopass/vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go
сгенерированный
поставляемый
|
@ -6,6 +6,7 @@ package terminal
|
|||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -241,3 +242,50 @@ func TestPasswordNotSaved(t *testing.T) {
|
|||
t.Fatalf("password was saved in history")
|
||||
}
|
||||
}
|
||||
|
||||
var setSizeTests = []struct {
|
||||
width, height int
|
||||
}{
|
||||
{40, 13},
|
||||
{80, 24},
|
||||
{132, 43},
|
||||
}
|
||||
|
||||
func TestTerminalSetSize(t *testing.T) {
|
||||
for _, setSize := range setSizeTests {
|
||||
c := &MockTerminal{
|
||||
toSend: []byte("password\r\x1b[A\r"),
|
||||
bytesPerRead: 1,
|
||||
}
|
||||
ss := NewTerminal(c, "> ")
|
||||
ss.SetSize(setSize.width, setSize.height)
|
||||
pw, _ := ss.ReadPassword("Password: ")
|
||||
if pw != "password" {
|
||||
t.Fatalf("failed to read password, got %s", pw)
|
||||
}
|
||||
if string(c.received) != "Password: \r\n" {
|
||||
t.Errorf("failed to set the temporary prompt expected %q, got %q", "Password: ", c.received)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMakeRawState(t *testing.T) {
|
||||
fd := int(os.Stdout.Fd())
|
||||
if !IsTerminal(fd) {
|
||||
t.Skip("stdout is not a terminal; skipping test")
|
||||
}
|
||||
|
||||
st, err := GetState(fd)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get terminal state from GetState: %s", err)
|
||||
}
|
||||
defer Restore(fd, st)
|
||||
raw, err := MakeRaw(fd)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get terminal state from MakeRaw: %s", err)
|
||||
}
|
||||
|
||||
if *st != *raw {
|
||||
t.Errorf("states do not match; was %v, expected %v", raw, st)
|
||||
}
|
||||
}
|
||||
|
|
11
vendor/github.com/howeyc/gopass/vendor/golang.org/x/crypto/ssh/terminal/util.go
сгенерированный
поставляемый
11
vendor/github.com/howeyc/gopass/vendor/golang.org/x/crypto/ssh/terminal/util.go
сгенерированный
поставляемый
|
@ -14,7 +14,7 @@
|
|||
// panic(err)
|
||||
// }
|
||||
// defer terminal.Restore(0, oldState)
|
||||
package terminal
|
||||
package terminal // import "golang.org/x/crypto/ssh/terminal"
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
@ -44,8 +44,13 @@ func MakeRaw(fd int) (*State, error) {
|
|||
}
|
||||
|
||||
newState := oldState.termios
|
||||
newState.Iflag &^= syscall.ISTRIP | syscall.INLCR | syscall.ICRNL | syscall.IGNCR | syscall.IXON | syscall.IXOFF
|
||||
newState.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.ISIG
|
||||
// This attempts to replicate the behaviour documented for cfmakeraw in
|
||||
// the termios(3) manpage.
|
||||
newState.Iflag &^= syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON
|
||||
newState.Oflag &^= syscall.OPOST
|
||||
newState.Lflag &^= syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN
|
||||
newState.Cflag &^= syscall.CSIZE | syscall.PARENB
|
||||
newState.Cflag |= syscall.CS8
|
||||
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
|
58
vendor/github.com/howeyc/gopass/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go
сгенерированный
поставляемый
Normal file
58
vendor/github.com/howeyc/gopass/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go
сгенерированный
поставляемый
Normal file
|
@ -0,0 +1,58 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package terminal provides support functions for dealing with terminals, as
|
||||
// commonly found on UNIX systems.
|
||||
//
|
||||
// Putting a terminal into raw mode is the most common requirement:
|
||||
//
|
||||
// oldState, err := terminal.MakeRaw(0)
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// defer terminal.Restore(0, oldState)
|
||||
package terminal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
type State struct{}
|
||||
|
||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
func IsTerminal(fd int) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// 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(fd int) (*State, error) {
|
||||
return nil, fmt.Errorf("terminal: MakeRaw not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
|
||||
// GetState returns the current state of a terminal which may be useful to
|
||||
// restore the terminal after a signal.
|
||||
func GetState(fd int) (*State, error) {
|
||||
return nil, fmt.Errorf("terminal: GetState not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
|
||||
// Restore restores the terminal connected to the given file descriptor to a
|
||||
// previous state.
|
||||
func Restore(fd int, state *State) error {
|
||||
return fmt.Errorf("terminal: Restore not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
|
||||
// GetSize returns the dimensions of the given terminal.
|
||||
func GetSize(fd int) (width, height int, err error) {
|
||||
return 0, 0, fmt.Errorf("terminal: GetSize not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
|
||||
// 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(fd int) ([]byte, error) {
|
||||
return nil, fmt.Errorf("terminal: ReadPassword not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
4
vendor/github.com/howeyc/gopass/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go
сгенерированный
поставляемый
4
vendor/github.com/howeyc/gopass/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go
сгенерированный
поставляемый
|
@ -87,8 +87,8 @@ func MakeRaw(fd int) (*State, error) {
|
|||
if e != 0 {
|
||||
return nil, error(e)
|
||||
}
|
||||
st &^= (enableEchoInput | enableProcessedInput | enableLineInput | enableProcessedOutput)
|
||||
_, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(st), 0)
|
||||
raw := st &^ (enableEchoInput | enableProcessedInput | enableLineInput | enableProcessedOutput)
|
||||
_, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(raw), 0)
|
||||
if e != 0 {
|
||||
return nil, error(e)
|
||||
}
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
// +build windows
|
||||
|
||||
package gopass
|
||||
|
||||
import "syscall"
|
||||
import "unsafe"
|
||||
import "unicode/utf16"
|
||||
|
||||
func getch() byte {
|
||||
modkernel32 := syscall.NewLazyDLL("kernel32.dll")
|
||||
procReadConsole := modkernel32.NewProc("ReadConsoleW")
|
||||
procGetConsoleMode := modkernel32.NewProc("GetConsoleMode")
|
||||
procSetConsoleMode := modkernel32.NewProc("SetConsoleMode")
|
||||
|
||||
var mode uint32
|
||||
pMode := &mode
|
||||
procGetConsoleMode.Call(uintptr(syscall.Stdin), uintptr(unsafe.Pointer(pMode)))
|
||||
|
||||
var echoMode, lineMode uint32
|
||||
echoMode = 4
|
||||
lineMode = 2
|
||||
var newMode uint32
|
||||
newMode = mode ^ (echoMode | lineMode)
|
||||
|
||||
procSetConsoleMode.Call(uintptr(syscall.Stdin), uintptr(newMode))
|
||||
|
||||
line := make([]uint16, 1)
|
||||
pLine := &line[0]
|
||||
var n uint16
|
||||
procReadConsole.Call(uintptr(syscall.Stdin), uintptr(unsafe.Pointer(pLine)), uintptr(len(line)), uintptr(unsafe.Pointer(&n)))
|
||||
|
||||
b := []byte(string(utf16.Decode(line)))
|
||||
|
||||
procSetConsoleMode.Call(uintptr(syscall.Stdin), uintptr(mode))
|
||||
|
||||
// Not sure how this could happen, but it did for someone
|
||||
if len(b) > 0 {
|
||||
return b[0]
|
||||
} else {
|
||||
return 13
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче