|
|
|
package utils
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"syscall"
|
|
|
|
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"golang.org/x/crypto/ssh/terminal"
|
|
|
|
)
|
|
|
|
|
|
|
|
// AskForPassphrase return passphrase using password input
|
|
|
|
func AskForPassphrase(prompt string) string {
|
|
|
|
fmt.Printf(prompt)
|
|
|
|
bytePassword, err := terminal.ReadPassword(int(syscall.Stdin))
|
|
|
|
if err != nil {
|
|
|
|
panic("read password error")
|
|
|
|
}
|
|
|
|
password := string(bytePassword)
|
|
|
|
fmt.Println()
|
|
|
|
|
|
|
|
return password
|
|
|
|
}
|
|
|
|
|
|
|
|
// readAllAsString reads the entire file contents as a string.
|
|
|
|
func readAllAsString(r io.Reader) (data string, err error) {
|
|
|
|
bytes, err := ioutil.ReadAll(r)
|
|
|
|
return string(bytes), err
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetPassphraseFromSource reads a passphrase such as a key-encrypting one
|
|
|
|
// non-interactively from the given source.
|
|
|
|
//
|
|
|
|
// The source can be "pass:password", "env:var", "file:pathname", "fd:number",
|
|
|
|
// or "stdin". See “PASS PHRASE ARGUMENTS” section of openssl(1) for details.
|
|
|
|
//
|
|
|
|
// When "stdin" or "fd:" is used,
|
|
|
|
// the standard input or the given file descriptor is exhausted.
|
|
|
|
// Therefore, this function should be called at most once per program
|
|
|
|
// invocation; the second call, if any, may return an empty string if "stdin"
|
|
|
|
// or "fd" is used.
|
|
|
|
func GetPassphraseFromSource(src string) (pass string, err error) {
|
|
|
|
switch src {
|
|
|
|
case "stdin":
|
|
|
|
return readAllAsString(os.Stdin)
|
|
|
|
}
|
|
|
|
methodArg := strings.SplitN(src, ":", 2)
|
|
|
|
if len(methodArg) < 2 {
|
|
|
|
return "", errors.Errorf("invalid passphrase reading method %#v", src)
|
|
|
|
}
|
|
|
|
method := methodArg[0]
|
|
|
|
arg := methodArg[1]
|
|
|
|
switch method {
|
|
|
|
case "pass":
|
|
|
|
return arg, nil
|
|
|
|
case "env":
|
|
|
|
pass, ok := os.LookupEnv(arg)
|
|
|
|
if !ok {
|
|
|
|
return "", errors.Errorf("environment variable %#v undefined", arg)
|
|
|
|
}
|
|
|
|
return pass, nil
|
|
|
|
case "file":
|
|
|
|
f, err := os.Open(arg)
|
|
|
|
if err != nil {
|
|
|
|
return "", errors.Wrapf(err, "cannot open file %#v", arg)
|
|
|
|
}
|
|
|
|
defer func() { _ = f.Close() }()
|
|
|
|
return readAllAsString(f)
|
|
|
|
case "fd":
|
|
|
|
fd, err := strconv.ParseUint(arg, 10, 0)
|
|
|
|
if err != nil {
|
|
|
|
return "", errors.Wrapf(err, "invalid fd literal %#v", arg)
|
|
|
|
}
|
|
|
|
f := os.NewFile(uintptr(fd), "(passphrase-source)")
|
|
|
|
if f == nil {
|
|
|
|
return "", errors.Errorf("cannot open fd %#v", fd)
|
|
|
|
}
|
|
|
|
defer func() { _ = f.Close() }()
|
|
|
|
return readAllAsString(f)
|
|
|
|
}
|
|
|
|
return "", errors.Errorf("invalid passphrase reading method %#v", method)
|
|
|
|
}
|