Adds pm key export

This commit is contained in:
Stephen McQuay 2018-02-25 10:10:08 -08:00
parent e18aee5b4f
commit 6f41544659
Signed by: sm
GPG Key ID: 4E4B72F479BA3CE5
2 changed files with 69 additions and 1 deletions

View File

@ -19,6 +19,7 @@ const keyUsage = `pm keyring: interact with pm's OpenPGP keyring
subcommands: subcommands:
create (c) -- create a fresh keypair create (c) -- create a fresh keypair
export (e) -- export a public key to stdout
list (ls) -- list configured key info list (ls) -- list configured key info
` `
@ -40,7 +41,7 @@ func main() {
if len(os.Args[1:]) < 2 { if len(os.Args[1:]) < 2 {
fatalf("pm keyring: insufficient args\n\nusage: %v", keyUsage) fatalf("pm keyring: insufficient args\n\nusage: %v", keyUsage)
} }
sub := os.Args[2] sub, args := os.Args[2], os.Args[3:]
switch sub { switch sub {
case "ls", "list": case "ls", "list":
if err := keyring.ListKeys(root, os.Stdout); err != nil { if err := keyring.ListKeys(root, os.Stdout); err != nil {
@ -71,6 +72,14 @@ func main() {
if err := keyring.NewKeyPair(root, name, email); err != nil { if err := keyring.NewKeyPair(root, name, email); err != nil {
fatalf("creating keypair: %v\n", err) fatalf("creating keypair: %v\n", err)
} }
case "export", "e":
if len(args) != 1 {
fatalf("missing email argument\n")
}
email := args[0]
if err := keyring.Export(root, os.Stdout, email); err != nil {
fatalf("exporting public key for %q: %v\n", email, err)
}
default: default:
fatalf("unknown keyring subcommand: %q\n\nusage: %v", sub, keyUsage) fatalf("unknown keyring subcommand: %q\n\nusage: %v", sub, keyUsage)
} }

View File

@ -9,6 +9,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"golang.org/x/crypto/openpgp" "golang.org/x/crypto/openpgp"
"golang.org/x/crypto/openpgp/armor"
"mcquay.me/fs" "mcquay.me/fs"
) )
@ -102,6 +103,37 @@ func ListKeys(root string, w io.Writer) error {
return nil return nil
} }
// Export prints pubkey information associated with email to w.
func Export(root string, w io.Writer, email string) error {
if err := ensureDir(root); err != nil {
return errors.Wrap(err, "can't find or create pgp dir")
}
srn, prn := getNames(root)
_, pubs, err := getELs(srn, prn)
if err != nil {
return errors.Wrap(err, "getting existing keyrings")
}
e, err := findKey(pubs, email)
if err != nil {
return errors.Wrap(err, "find key")
}
aw, err := armor.Encode(w, openpgp.PublicKeyType, nil)
if err != nil {
return errors.Wrap(err, "creating armor encoder")
}
if err := e.Serialize(aw); err != nil {
return errors.Wrap(err, "serializing key")
}
if err := aw.Close(); err != nil {
return errors.Wrap(err, "closing armor encoder")
}
fmt.Fprintf(w, "\n")
return nil
}
func pGPDir(root string) string { func pGPDir(root string) string {
return filepath.Join(root, "var", "lib", "pm", "pgp") return filepath.Join(root, "var", "lib", "pm", "pgp")
} }
@ -153,3 +185,30 @@ func getELs(secring, pubring string) (openpgp.EntityList, openpgp.EntityList, er
} }
return sr, pr, nil return sr, pr, nil
} }
func findKey(el openpgp.EntityList, id string) (*openpgp.Entity, error) {
var e *openpgp.Entity
if strings.Contains(id, "@") {
es := openpgp.EntityList{}
for _, p := range el {
for _, v := range p.Identities {
if id == v.UserId.Email {
es = append(es, p)
}
}
}
if len(es) == 1 {
return es[0], nil
}
if len(es) > 1 {
return nil, errors.New("too many keys matched; try searching by key id?")
}
} else {
for _, p := range el {
if id == p.PrimaryKey.KeyIdShortString() {
return p, nil
}
}
}
return e, fmt.Errorf("key %q not found", id)
}