mirror of
				https://github.com/containers/podman.git
				synced 2025-10-31 18:08:51 +08:00 
			
		
		
		
	 56d6ee0808
			
		
	
	56d6ee0808
	
	
	
		
			
			golang.org/x/crypto/ssh/terminal is deprecated. The package was moved to golang.org/x/term. golang.org/x/crypto/ssh/terminal was already just calling golang.org/x/term itslef so there are no functional changes. Signed-off-by: Paul Holzinger <pholzing@redhat.com>
		
			
				
	
	
		
			135 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			135 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package terminal
 | |
| 
 | |
| import (
 | |
| 	"bufio"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"io/ioutil"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"sync"
 | |
| 
 | |
| 	"github.com/containers/storage/pkg/homedir"
 | |
| 	"github.com/sirupsen/logrus"
 | |
| 	"golang.org/x/crypto/ssh"
 | |
| 	"golang.org/x/crypto/ssh/knownhosts"
 | |
| 	"golang.org/x/term"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	passPhrase   []byte
 | |
| 	phraseSync   sync.Once
 | |
| 	password     []byte
 | |
| 	passwordSync sync.Once
 | |
| )
 | |
| 
 | |
| // ReadPassword prompts for a secret and returns value input by user from stdin
 | |
| // Unlike terminal.ReadPassword(), $(echo $SECRET | podman...) is supported.
 | |
| // Additionally, all input after `<secret>/n` is queued to podman command.
 | |
| func ReadPassword(prompt string) (pw []byte, err error) {
 | |
| 	fd := int(os.Stdin.Fd())
 | |
| 	if term.IsTerminal(fd) {
 | |
| 		fmt.Fprint(os.Stderr, prompt)
 | |
| 		pw, err = term.ReadPassword(fd)
 | |
| 		fmt.Fprintln(os.Stderr)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	var b [1]byte
 | |
| 	for {
 | |
| 		n, err := os.Stdin.Read(b[:])
 | |
| 		// terminal.ReadPassword discards any '\r', so we do the same
 | |
| 		if n > 0 && b[0] != '\r' {
 | |
| 			if b[0] == '\n' {
 | |
| 				return pw, nil
 | |
| 			}
 | |
| 			pw = append(pw, b[0])
 | |
| 			// limit size, so that a wrong input won't fill up the memory
 | |
| 			if len(pw) > 1024 {
 | |
| 				err = errors.New("password too long, 1024 byte limit")
 | |
| 			}
 | |
| 		}
 | |
| 		if err != nil {
 | |
| 			// terminal.ReadPassword accepts EOF-terminated passwords
 | |
| 			// if non-empty, so we do the same
 | |
| 			if err == io.EOF && len(pw) > 0 {
 | |
| 				err = nil
 | |
| 			}
 | |
| 			return pw, err
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func PublicKey(path string, passphrase []byte) (ssh.Signer, error) {
 | |
| 	key, err := ioutil.ReadFile(path)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	signer, err := ssh.ParsePrivateKey(key)
 | |
| 	if err != nil {
 | |
| 		if _, ok := err.(*ssh.PassphraseMissingError); !ok {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		if len(passphrase) == 0 {
 | |
| 			passphrase = ReadPassphrase()
 | |
| 		}
 | |
| 		return ssh.ParsePrivateKeyWithPassphrase(key, passphrase)
 | |
| 	}
 | |
| 	return signer, nil
 | |
| }
 | |
| 
 | |
| func ReadPassphrase() []byte {
 | |
| 	phraseSync.Do(func() {
 | |
| 		secret, err := ReadPassword("Key Passphrase: ")
 | |
| 		if err != nil {
 | |
| 			secret = []byte{}
 | |
| 		}
 | |
| 		passPhrase = secret
 | |
| 	})
 | |
| 	return passPhrase
 | |
| }
 | |
| 
 | |
| func ReadLogin() []byte {
 | |
| 	passwordSync.Do(func() {
 | |
| 		secret, err := ReadPassword("Login password: ")
 | |
| 		if err != nil {
 | |
| 			secret = []byte{}
 | |
| 		}
 | |
| 		password = secret
 | |
| 	})
 | |
| 	return password
 | |
| }
 | |
| 
 | |
| func HostKey(host string) ssh.PublicKey {
 | |
| 	// parse OpenSSH known_hosts file
 | |
| 	// ssh or use ssh-keyscan to get initial key
 | |
| 	knownHosts := filepath.Join(homedir.Get(), ".ssh", "known_hosts")
 | |
| 	fd, err := os.Open(knownHosts)
 | |
| 	if err != nil {
 | |
| 		logrus.Error(err)
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	// support -H parameter for ssh-keyscan
 | |
| 	hashhost := knownhosts.HashHostname(host)
 | |
| 
 | |
| 	scanner := bufio.NewScanner(fd)
 | |
| 	for scanner.Scan() {
 | |
| 		_, hosts, key, _, _, err := ssh.ParseKnownHosts(scanner.Bytes())
 | |
| 		if err != nil {
 | |
| 			logrus.Errorf("Failed to parse known_hosts: %s", scanner.Text())
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		for _, h := range hosts {
 | |
| 			if h == host || h == hashhost {
 | |
| 				return key
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 |