aboutsummaryrefslogtreecommitdiffstats
path: root/lib/crypto/util/cleartext.go
diff options
context:
space:
mode:
Diffstat (limited to 'lib/crypto/util/cleartext.go')
-rw-r--r--lib/crypto/util/cleartext.go69
1 files changed, 69 insertions, 0 deletions
diff --git a/lib/crypto/util/cleartext.go b/lib/crypto/util/cleartext.go
new file mode 100644
index 00000000..fe6faa89
--- /dev/null
+++ b/lib/crypto/util/cleartext.go
@@ -0,0 +1,69 @@
+package cryptoutil
+
+import (
+ "bytes"
+ "errors"
+ "io"
+ "strings"
+
+ "git.sr.ht/~rjarry/aerc/app"
+ "git.sr.ht/~rjarry/aerc/lib/rfc822"
+ "github.com/emersion/go-message/mail"
+)
+
+func Cleartext(r io.Reader, header mail.Header) ([]byte, error) {
+ msg, err := app.CryptoProvider().Decrypt(
+ rfc822.NewCRLFReader(r), app.DecryptKeys)
+ if err != nil {
+ return nil, errors.New("decrypt error")
+ }
+ full, err := createMessage(header, msg.Body)
+ if err != nil {
+ return nil, errors.New("failed to create decrypted message")
+ }
+ return full, nil
+}
+
+func createMessage(header mail.Header, body io.Reader) ([]byte, error) {
+ e, err := rfc822.ReadMessage(body)
+ if err != nil {
+ return nil, err
+ }
+
+ // copy the header values from the "decrypted body". This should set
+ // the correct content type.
+ hf := e.Header.Fields()
+ for hf.Next() {
+ header.Set(hf.Key(), hf.Value())
+ }
+
+ ctype, params, err := header.ContentType()
+ if err != nil {
+ return nil, err
+ }
+
+ // in case there remains a multipart/{encrypted,signed} content type,
+ // manually correct them to multipart/mixed as a fallback.
+ ct := strings.ToLower(ctype)
+ if strings.Contains(ct, "multipart/encrypted") ||
+ strings.Contains(ct, "multipart/signed") {
+ delete(params, "protocol")
+ delete(params, "micalg")
+ header.SetContentType("multipart/mixed", params)
+ }
+
+ // a SingleInlineWriter is sufficient since the "decrypted body"
+ // already contains the proper boundaries of the parts; we just want to
+ // combine it with the headers.
+ var message bytes.Buffer
+ w, err := mail.CreateSingleInlineWriter(&message, header)
+ if err != nil {
+ return nil, err
+ }
+ if _, err := io.Copy(w, e.Body); err != nil {
+ return nil, err
+ }
+ w.Close()
+
+ return message.Bytes(), nil
+}