From 1063e5b6eca536af07040ba929e872c3fc256444 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 18 Jan 2024 16:21:43 +0000 Subject: [PATCH] email: make PGP private key optional Services other than meta.sr.ht don't really have a use for the private PGP key. Add a CanPGPSign method so that meta.sr.ht can emit a warning or error when the PGP key is missing. --- email/worker.go | 61 ++++++++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/email/worker.go b/email/worker.go index 0123fc0b985a08b01daf6d7f1cfcbec18e64dcc3..bb74a0ca183a5ac628111802e4d122287cc176b4 100644 --- a/email/worker.go +++ b/email/worker.go @@ -134,9 +134,13 @@ func EnqueueStd(ctx context.Context, header mail.Header, strings.Join(rcpts, ", "), err.Error()) } - cleartext, err = prepareSigned(header, &buf, queue.entity) - if err != nil { - log.Fatalf("Signing mail failed: %v", err) + if queue.entity != nil { + cleartext, err = prepareSigned(header, &buf, queue.entity) + if err != nil { + log.Fatalf("Signing mail failed: %v", err) + } + } else { + cleartext = nopWriteCloser{&buf} } } defer cleartext.Close() @@ -157,6 +161,14 @@ func EnqueueStd(ctx context.Context, header mail.Header, return queue.Enqueue(NewTask(&buf, rcpts)) } +type nopWriteCloser struct { + io.Writer +} + +func (nopWriteCloser) Close() error { + return nil +} + type Queue struct { *work.Queue smtpFrom *mail.Address @@ -164,6 +176,11 @@ type Queue struct { entity *openpgp.Entity } +// CanPGPSign checks whether emails sent via the queue are signed via OpenPGP. +func (q *Queue) CanPGPSign() bool { + return q.entity != nil +} + // Creates a new email processing queue. func NewQueue(conf ini.File) *Queue { smtpFrom, ok := conf.Get("mail", "smtp-from") @@ -187,27 +204,25 @@ func NewQueue(conf ini.File) *Queue { Address: ownerEmail, } - privKeyPath, ok := conf.Get("mail", "pgp-privkey") - if !ok { - panic("Expected [mail]pgp-privkey in config") - } - - privKeyFile, err := os.Open(privKeyPath) - if err != nil { - panic(fmt.Errorf("Failed to open [mail]pgp-privkey: %v", err)) - } - defer privKeyFile.Close() + var entity *openpgp.Entity + if privKeyPath, ok := conf.Get("mail", "pgp-privkey"); ok { + privKeyFile, err := os.Open(privKeyPath) + if err != nil { + panic(fmt.Errorf("Failed to open [mail]pgp-privkey: %v", err)) + } + defer privKeyFile.Close() - keyring, err := openpgp.ReadArmoredKeyRing(privKeyFile) - if err != nil { - panic(fmt.Errorf("Failed to read PGP key ring from [mail]pgp-privkey: %v", err)) - } - if len(keyring) != 1 { - panic("Expected [mail]pgp-privkey to contain one key") - } - entity := keyring[0] - if entity.PrivateKey == nil || entity.PrivateKey.Encrypted { - panic("Failed to load [mail]pgp-privkey for email signature") + keyring, err := openpgp.ReadArmoredKeyRing(privKeyFile) + if err != nil { + panic(fmt.Errorf("Failed to read PGP key ring from [mail]pgp-privkey: %v", err)) + } + if len(keyring) != 1 { + panic("Expected [mail]pgp-privkey to contain one key") + } + entity = keyring[0] + if entity.PrivateKey == nil || entity.PrivateKey.Encrypted { + panic("Failed to load [mail]pgp-privkey for email signature") + } } return &Queue{