aboutsummaryrefslogtreecommitdiffstats
path: root/lib/crypto/gpg/gpgbin
diff options
context:
space:
mode:
Diffstat (limited to 'lib/crypto/gpg/gpgbin')
-rw-r--r--lib/crypto/gpg/gpgbin/decrypt.go21
-rw-r--r--lib/crypto/gpg/gpgbin/encrypt.go7
-rw-r--r--lib/crypto/gpg/gpgbin/gpgbin.go69
-rw-r--r--lib/crypto/gpg/gpgbin/sign.go8
-rw-r--r--lib/crypto/gpg/gpgbin/verify.go3
5 files changed, 44 insertions, 64 deletions
diff --git a/lib/crypto/gpg/gpgbin/decrypt.go b/lib/crypto/gpg/gpgbin/decrypt.go
index 86d5575e..65f7a73d 100644
--- a/lib/crypto/gpg/gpgbin/decrypt.go
+++ b/lib/crypto/gpg/gpgbin/decrypt.go
@@ -2,6 +2,7 @@ package gpgbin
import (
"bytes"
+ "errors"
"io"
"git.sr.ht/~rjarry/aerc/models"
@@ -18,19 +19,17 @@ func Decrypt(r io.Reader) (*models.MessageDetails, error) {
args := []string{"--decrypt"}
g := newGpg(bytes.NewReader(orig), args)
_ = g.cmd.Run()
- outRdr := bytes.NewReader(g.stdout.Bytes())
// Always parse stdout, even if there was an error running command.
// We'll find the error in the parsing
- err = parse(outRdr, md)
- if err != nil {
- err = parseError(g.stderr.String())
- switch GPGErrors[err.Error()] {
- case ERROR_NO_PGP_DATA_FOUND:
- md.Body = bytes.NewReader(orig)
- return md, nil
- default:
- return nil, err
- }
+ err = parseStatusFd(bytes.NewReader(g.stderr.Bytes()), md)
+
+ if errors.Is(err, NoValidOpenPgpData) {
+ md.Body = bytes.NewReader(orig)
+ return md, nil
+ } else if err != nil {
+ return nil, err
}
+
+ md.Body = bytes.NewReader(g.stdout.Bytes())
return md, nil
}
diff --git a/lib/crypto/gpg/gpgbin/encrypt.go b/lib/crypto/gpg/gpgbin/encrypt.go
index 712bb327..91e0999a 100644
--- a/lib/crypto/gpg/gpgbin/encrypt.go
+++ b/lib/crypto/gpg/gpgbin/encrypt.go
@@ -23,14 +23,11 @@ func Encrypt(r io.Reader, to []string, from string) ([]byte, error) {
g := newGpg(r, args)
_ = g.cmd.Run()
- outRdr := bytes.NewReader(g.stdout.Bytes())
var md models.MessageDetails
- err := parse(outRdr, &md)
+ err := parseStatusFd(bytes.NewReader(g.stderr.Bytes()), &md)
if err != nil {
return nil, fmt.Errorf("gpg: failure to encrypt: %w. check public key(s)", err)
}
- var buf bytes.Buffer
- _, _ = io.Copy(&buf, md.Body)
- return buf.Bytes(), nil
+ return g.stdout.Bytes(), nil
}
diff --git a/lib/crypto/gpg/gpgbin/gpgbin.go b/lib/crypto/gpg/gpgbin/gpgbin.go
index a7eafacd..b4985328 100644
--- a/lib/crypto/gpg/gpgbin/gpgbin.go
+++ b/lib/crypto/gpg/gpgbin/gpgbin.go
@@ -3,7 +3,6 @@ package gpgbin
import (
"bufio"
"bytes"
- "errors"
"fmt"
"io"
"os/exec"
@@ -25,7 +24,7 @@ type gpg struct {
// newGpg creates a new gpg command with buffers attached
func newGpg(stdin io.Reader, args []string) *gpg {
g := new(gpg)
- g.cmd = exec.Command("gpg", "--status-fd", "1", "--batch")
+ g.cmd = exec.Command("gpg", "--status-fd", "2", "--log-file", "/dev/null", "--batch")
g.cmd.Args = append(g.cmd.Args, args...)
g.cmd.Stdin = stdin
g.cmd.Stdout = &g.stdout
@@ -36,19 +35,6 @@ func newGpg(stdin io.Reader, args []string) *gpg {
return g
}
-// parseError parses errors returned by gpg that don't show up with a [GNUPG:]
-// prefix
-func parseError(s string) error {
- lines := strings.Split(s, "\n")
- for _, line := range lines {
- line = strings.ToLower(line)
- if GPGErrors[line] > 0 {
- return errors.New(line)
- }
- }
- return errors.New(strings.Join(lines, ", "))
-}
-
// fields returns the field name from --status-fd output. See:
// https://github.com/gpg/gnupg/blob/master/doc/DETAILS
func field(s string) string {
@@ -119,25 +105,15 @@ func longKeyToUint64(key string) (uint64, error) {
}
// parse parses the output of gpg --status-fd
-func parse(r io.Reader, md *models.MessageDetails) error {
+func parseStatusFd(r io.Reader, md *models.MessageDetails) error {
var err error
- var msgContent []byte
- var msgCollecting bool
- newLine := []byte("\r\n")
scanner := bufio.NewScanner(r)
for scanner.Scan() {
line := scanner.Text()
if field(line) == "PLAINTEXT_LENGTH" {
continue
}
- if strings.HasPrefix(line, "[GNUPG:]") {
- msgCollecting = false
- log.Tracef(line)
- }
- if msgCollecting {
- msgContent = append(msgContent, scanner.Bytes()...)
- msgContent = append(msgContent, newLine...)
- }
+ log.Tracef(line)
switch field(line) {
case "ENC_TO":
@@ -149,9 +125,7 @@ func parse(r io.Reader, md *models.MessageDetails) error {
return err
}
case "DECRYPTION_FAILED":
- return fmt.Errorf("gpg: decryption failed")
- case "PLAINTEXT":
- msgCollecting = true
+ return EncryptionFailed
case "NEWSIG":
md.IsSigned = true
case "GOODSIG":
@@ -211,30 +185,32 @@ func parse(r io.Reader, md *models.MessageDetails) error {
if t[2] == "10" {
return fmt.Errorf("gpg: public key of %s is not trusted", t[3])
}
- case "BEGIN_ENCRYPTION":
- msgCollecting = true
case "SIG_CREATED":
fields := strings.Split(line, " ")
micalg, err := strconv.Atoi(fields[4])
if err != nil {
- return fmt.Errorf("gpg: micalg not found")
+ return MicalgNotFound
}
md.Micalg = micalgs[micalg]
- msgCollecting = true
case "VALIDSIG":
fields := strings.Split(line, " ")
micalg, err := strconv.Atoi(fields[9])
if err != nil {
- return fmt.Errorf("gpg: micalg not found")
+ return MicalgNotFound
}
md.Micalg = micalgs[micalg]
case "NODATA":
- md.SignatureError = "gpg: no signature packet found"
+ t := strings.SplitN(line, " ", 3)
+ if t[2] == "4" {
+ md.SignatureError = "gpg: no signature packet found"
+ }
+ if t[2] == "1" {
+ return NoValidOpenPgpData
+ }
case "FAILURE":
return fmt.Errorf("%s", strings.TrimPrefix(line, "[GNUPG:] "))
}
}
- md.Body = bytes.NewReader(msgContent)
return nil
}
@@ -250,14 +226,25 @@ func parseDecryptionKey(l string) (uint64, error) {
return fprUint64, nil
}
-type GPGError int32
+type StatusFdParsingError int32
const (
- ERROR_NO_PGP_DATA_FOUND GPGError = iota + 1
+ EncryptionFailed StatusFdParsingError = iota + 1
+ MicalgNotFound
+ NoValidOpenPgpData
)
-var GPGErrors = map[string]GPGError{
- "gpg: no valid openpgp data found.": ERROR_NO_PGP_DATA_FOUND,
+func (err StatusFdParsingError) Error() string {
+ switch err {
+ case EncryptionFailed:
+ return "gpg: decryption failed"
+ case MicalgNotFound:
+ return "gpg: micalg not found"
+ case NoValidOpenPgpData:
+ return "gpg: no valid OpenPGP data found"
+ default:
+ return "gpg: unknown status fd parsing error"
+ }
}
// micalgs represent hash algorithms for signatures. These are ignored by many
diff --git a/lib/crypto/gpg/gpgbin/sign.go b/lib/crypto/gpg/gpgbin/sign.go
index 163aedfd..63bbd15c 100644
--- a/lib/crypto/gpg/gpgbin/sign.go
+++ b/lib/crypto/gpg/gpgbin/sign.go
@@ -19,13 +19,11 @@ func Sign(r io.Reader, from string) ([]byte, string, error) {
g := newGpg(r, args)
_ = g.cmd.Run()
- outRdr := bytes.NewReader(g.stdout.Bytes())
var md models.MessageDetails
- err := parse(outRdr, &md)
+ err := parseStatusFd(bytes.NewReader(g.stderr.Bytes()), &md)
if err != nil {
return nil, "", fmt.Errorf("failed to parse messagedetails: %w", err)
}
- var buf bytes.Buffer
- _, _ = io.Copy(&buf, md.Body)
- return buf.Bytes(), md.Micalg, nil
+
+ return g.stdout.Bytes(), md.Micalg, nil
}
diff --git a/lib/crypto/gpg/gpgbin/verify.go b/lib/crypto/gpg/gpgbin/verify.go
index 8208dc0d..a3ea4b4a 100644
--- a/lib/crypto/gpg/gpgbin/verify.go
+++ b/lib/crypto/gpg/gpgbin/verify.go
@@ -30,9 +30,8 @@ func Verify(m io.Reader, s io.Reader) (*models.MessageDetails, error) {
g := newGpg(bytes.NewReader(orig), args)
_ = g.cmd.Run()
- out := bytes.NewReader(g.stdout.Bytes())
md := new(models.MessageDetails)
- _ = parse(out, md)
+ _ = parseStatusFd(bytes.NewReader(g.stderr.Bytes()), md)
md.Body = bytes.NewReader(orig)