github.com/hashicorp/terraform-plugin-sdk@v1.17.2/internal/vault/helper/pgpkeys/flag.go (about)

     1  package pgpkeys
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/base64"
     6  	"errors"
     7  	"fmt"
     8  	"os"
     9  	"strings"
    10  
    11  	"github.com/hashicorp/errwrap"
    12  	"github.com/keybase/go-crypto/openpgp"
    13  )
    14  
    15  // PGPPubKeyFiles implements the flag.Value interface and allows parsing and
    16  // reading a list of PGP public key files.
    17  type PubKeyFilesFlag []string
    18  
    19  func (p *PubKeyFilesFlag) String() string {
    20  	return fmt.Sprint(*p)
    21  }
    22  
    23  func (p *PubKeyFilesFlag) Set(val string) error {
    24  	if len(*p) > 0 {
    25  		return errors.New("can only be specified once")
    26  	}
    27  
    28  	keys, err := ParsePGPKeys(strings.Split(val, ","))
    29  	if err != nil {
    30  		return err
    31  	}
    32  
    33  	*p = PubKeyFilesFlag(keys)
    34  	return nil
    35  }
    36  
    37  // ParsePGPKeys takes a list of PGP keys and parses them either using keybase
    38  // or reading them from disk and returns the "expanded" list of pgp keys in
    39  // the same order.
    40  func ParsePGPKeys(keyfiles []string) ([]string, error) {
    41  	keys := make([]string, len(keyfiles))
    42  
    43  	keybaseMap, err := FetchKeybasePubkeys(keyfiles)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  
    48  	for i, keyfile := range keyfiles {
    49  		keyfile = strings.TrimSpace(keyfile)
    50  
    51  		if strings.HasPrefix(keyfile, kbPrefix) {
    52  			key, ok := keybaseMap[keyfile]
    53  			if !ok || key == "" {
    54  				return nil, fmt.Errorf("keybase user %q not found", strings.TrimPrefix(keyfile, kbPrefix))
    55  			}
    56  			keys[i] = key
    57  			continue
    58  		}
    59  
    60  		pgpStr, err := ReadPGPFile(keyfile)
    61  		if err != nil {
    62  			return nil, err
    63  		}
    64  		keys[i] = pgpStr
    65  	}
    66  
    67  	return keys, nil
    68  }
    69  
    70  // ReadPGPFile reads the given PGP file from disk.
    71  func ReadPGPFile(path string) (string, error) {
    72  	if path[0] == '@' {
    73  		path = path[1:]
    74  	}
    75  	f, err := os.Open(path)
    76  	if err != nil {
    77  		return "", err
    78  	}
    79  	defer f.Close()
    80  	buf := bytes.NewBuffer(nil)
    81  	_, err = buf.ReadFrom(f)
    82  	if err != nil {
    83  		return "", err
    84  	}
    85  
    86  	// First parse as an armored keyring file, if that doesn't work, treat it as a straight binary/b64 string
    87  	keyReader := bytes.NewReader(buf.Bytes())
    88  	entityList, err := openpgp.ReadArmoredKeyRing(keyReader)
    89  	if err == nil {
    90  		if len(entityList) != 1 {
    91  			return "", fmt.Errorf("more than one key found in file %q", path)
    92  		}
    93  		if entityList[0] == nil {
    94  			return "", fmt.Errorf("primary key was nil for file %q", path)
    95  		}
    96  
    97  		serializedEntity := bytes.NewBuffer(nil)
    98  		err = entityList[0].Serialize(serializedEntity)
    99  		if err != nil {
   100  			return "", errwrap.Wrapf(fmt.Sprintf("error serializing entity for file %q: {{err}}", path), err)
   101  		}
   102  
   103  		return base64.StdEncoding.EncodeToString(serializedEntity.Bytes()), nil
   104  	}
   105  
   106  	_, err = base64.StdEncoding.DecodeString(buf.String())
   107  	if err == nil {
   108  		return buf.String(), nil
   109  	}
   110  	return base64.StdEncoding.EncodeToString(buf.Bytes()), nil
   111  
   112  }