forked from toolshed/abra
chore: vendor
This commit is contained in:
210
vendor/github.com/theupdateframework/notary/passphrase/passphrase.go
generated
vendored
Normal file
210
vendor/github.com/theupdateframework/notary/passphrase/passphrase.go
generated
vendored
Normal file
@ -0,0 +1,210 @@
|
||||
// Package passphrase is a utility function for managing passphrase
|
||||
// for TUF and Notary keys.
|
||||
package passphrase
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/theupdateframework/notary"
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
const (
|
||||
idBytesToDisplay = 7
|
||||
tufRootAlias = "root"
|
||||
tufRootKeyGenerationWarning = `You are about to create a new root signing key passphrase. This passphrase
|
||||
will be used to protect the most sensitive key in your signing system. Please
|
||||
choose a long, complex passphrase and be careful to keep the password and the
|
||||
key file itself secure and backed up. It is highly recommended that you use a
|
||||
password manager to generate the passphrase and keep it safe. There will be no
|
||||
way to recover this key. You can find the key in your config directory.`
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrTooShort is returned if the passphrase entered for a new key is
|
||||
// below the minimum length
|
||||
ErrTooShort = errors.New("Passphrase too short")
|
||||
|
||||
// ErrDontMatch is returned if the two entered passphrases don't match.
|
||||
// new key is below the minimum length
|
||||
ErrDontMatch = errors.New("The entered passphrases do not match")
|
||||
|
||||
// ErrTooManyAttempts is returned if the maximum number of passphrase
|
||||
// entry attempts is reached.
|
||||
ErrTooManyAttempts = errors.New("Too many attempts")
|
||||
|
||||
// ErrNoInput is returned if we do not have a valid input method for passphrases
|
||||
ErrNoInput = errors.New("Please either use environment variables or STDIN with a terminal to provide key passphrases")
|
||||
)
|
||||
|
||||
// PromptRetriever returns a new Retriever which will provide a prompt on stdin
|
||||
// and stdout to retrieve a passphrase. stdin will be checked if it is a terminal,
|
||||
// else the PromptRetriever will error when attempting to retrieve a passphrase.
|
||||
// Upon successful passphrase retrievals, the passphrase will be cached such that
|
||||
// subsequent prompts will produce the same passphrase.
|
||||
func PromptRetriever() notary.PassRetriever {
|
||||
if !term.IsTerminal(int(os.Stdin.Fd())) {
|
||||
return func(string, string, bool, int) (string, bool, error) {
|
||||
return "", false, ErrNoInput
|
||||
}
|
||||
}
|
||||
return PromptRetrieverWithInOut(os.Stdin, os.Stdout, nil)
|
||||
}
|
||||
|
||||
type boundRetriever struct {
|
||||
in io.Reader
|
||||
out io.Writer
|
||||
aliasMap map[string]string
|
||||
passphraseCache map[string]string
|
||||
}
|
||||
|
||||
func (br *boundRetriever) getPassphrase(keyName, alias string, createNew bool, numAttempts int) (string, bool, error) {
|
||||
if numAttempts == 0 {
|
||||
if alias == tufRootAlias && createNew {
|
||||
fmt.Fprintln(br.out, tufRootKeyGenerationWarning)
|
||||
}
|
||||
|
||||
if pass, ok := br.passphraseCache[alias]; ok {
|
||||
return pass, false, nil
|
||||
}
|
||||
} else if !createNew { // per `if`, numAttempts > 0 if we're at this `else`
|
||||
if numAttempts > 3 {
|
||||
return "", true, ErrTooManyAttempts
|
||||
}
|
||||
fmt.Fprintln(br.out, "Passphrase incorrect. Please retry.")
|
||||
}
|
||||
|
||||
// passphrase not cached and we're not aborting, get passphrase from user!
|
||||
return br.requestPassphrase(keyName, alias, createNew, numAttempts)
|
||||
}
|
||||
|
||||
func (br *boundRetriever) requestPassphrase(keyName, alias string, createNew bool, numAttempts int) (string, bool, error) {
|
||||
// Figure out if we should display a different string for this alias
|
||||
displayAlias := alias
|
||||
if val, ok := br.aliasMap[alias]; ok {
|
||||
displayAlias = val
|
||||
}
|
||||
|
||||
indexOfLastSeparator := strings.LastIndex(keyName, string(filepath.Separator))
|
||||
if indexOfLastSeparator == -1 {
|
||||
indexOfLastSeparator = 0
|
||||
}
|
||||
|
||||
var shortName string
|
||||
if len(keyName) > indexOfLastSeparator+idBytesToDisplay {
|
||||
if indexOfLastSeparator > 0 {
|
||||
keyNamePrefix := keyName[:indexOfLastSeparator]
|
||||
keyNameID := keyName[indexOfLastSeparator+1 : indexOfLastSeparator+idBytesToDisplay+1]
|
||||
shortName = keyNameID + " (" + keyNamePrefix + ")"
|
||||
} else {
|
||||
shortName = keyName[indexOfLastSeparator : indexOfLastSeparator+idBytesToDisplay]
|
||||
}
|
||||
}
|
||||
|
||||
withID := fmt.Sprintf(" with ID %s", shortName)
|
||||
if shortName == "" {
|
||||
withID = ""
|
||||
}
|
||||
|
||||
switch {
|
||||
case createNew:
|
||||
fmt.Fprintf(br.out, "Enter passphrase for new %s key%s: ", displayAlias, withID)
|
||||
case displayAlias == "yubikey":
|
||||
fmt.Fprintf(br.out, "Enter the %s for the attached Yubikey: ", keyName)
|
||||
default:
|
||||
fmt.Fprintf(br.out, "Enter passphrase for %s key%s: ", displayAlias, withID)
|
||||
}
|
||||
|
||||
stdin := bufio.NewReader(br.in)
|
||||
passphrase, err := GetPassphrase(stdin)
|
||||
fmt.Fprintln(br.out)
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
|
||||
retPass := strings.TrimSpace(string(passphrase))
|
||||
|
||||
if createNew {
|
||||
err = br.verifyAndConfirmPassword(stdin, retPass, displayAlias, withID)
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
}
|
||||
|
||||
br.cachePassword(alias, retPass)
|
||||
|
||||
return retPass, false, nil
|
||||
}
|
||||
|
||||
func (br *boundRetriever) verifyAndConfirmPassword(stdin *bufio.Reader, retPass, displayAlias, withID string) error {
|
||||
if len(retPass) < 8 {
|
||||
fmt.Fprintln(br.out, "Passphrase is too short. Please use a password manager to generate and store a good random passphrase.")
|
||||
return ErrTooShort
|
||||
}
|
||||
|
||||
fmt.Fprintf(br.out, "Repeat passphrase for new %s key%s: ", displayAlias, withID)
|
||||
|
||||
confirmation, err := GetPassphrase(stdin)
|
||||
fmt.Fprintln(br.out)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
confirmationStr := strings.TrimSpace(string(confirmation))
|
||||
|
||||
if retPass != confirmationStr {
|
||||
fmt.Fprintln(br.out, "Passphrases do not match. Please retry.")
|
||||
return ErrDontMatch
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (br *boundRetriever) cachePassword(alias, retPass string) {
|
||||
br.passphraseCache[alias] = retPass
|
||||
}
|
||||
|
||||
// PromptRetrieverWithInOut returns a new Retriever which will provide a
|
||||
// prompt using the given in and out readers. The passphrase will be cached
|
||||
// such that subsequent prompts will produce the same passphrase.
|
||||
// aliasMap can be used to specify display names for TUF key aliases. If aliasMap
|
||||
// is nil, a sensible default will be used.
|
||||
func PromptRetrieverWithInOut(in io.Reader, out io.Writer, aliasMap map[string]string) notary.PassRetriever {
|
||||
bound := &boundRetriever{
|
||||
in: in,
|
||||
out: out,
|
||||
aliasMap: aliasMap,
|
||||
passphraseCache: make(map[string]string),
|
||||
}
|
||||
|
||||
return bound.getPassphrase
|
||||
}
|
||||
|
||||
// ConstantRetriever returns a new Retriever which will return a constant string
|
||||
// as a passphrase.
|
||||
func ConstantRetriever(constantPassphrase string) notary.PassRetriever {
|
||||
return func(k, a string, c bool, n int) (string, bool, error) {
|
||||
return constantPassphrase, false, nil
|
||||
}
|
||||
}
|
||||
|
||||
// GetPassphrase get the passphrase from bufio.Reader or from terminal.
|
||||
// If typing on the terminal, we disable terminal to echo the passphrase.
|
||||
func GetPassphrase(in *bufio.Reader) ([]byte, error) {
|
||||
var (
|
||||
passphrase []byte
|
||||
err error
|
||||
)
|
||||
|
||||
if term.IsTerminal(int(os.Stdin.Fd())) {
|
||||
passphrase, err = term.ReadPassword(int(os.Stdin.Fd()))
|
||||
} else {
|
||||
passphrase, err = in.ReadBytes('\n')
|
||||
}
|
||||
|
||||
return passphrase, err
|
||||
}
|
Reference in New Issue
Block a user