aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorKoni Marti <koni.marti@gmail.com>2024-06-14 23:06:56 +0200
committerRobin Jarry <robin@jarry.cc>2024-08-20 11:54:34 +0200
commit108a8ca1d2728dc7b4258fb455b78fab1f6a063d (patch)
tree16f442d07d246bad0ab30b14ed14aea7ac188086 /lib
parent7558ccab40dabc44e810342534cdcd0ca20929a1 (diff)
downloadaerc-108a8ca1d2728dc7b4258fb455b78fab1f6a063d.tar.gz
cryptoutil: implement cleartext function
Implement a cleartext function in the cryptoutil package to decrypt an encrypted message to cleartext and construct a valid rfc2822 message. The headers from the decrypt message body will be merged with the original headers to create a fully decrypted message. Implements: https://todo.sr.ht/~rjarry/aerc/238 Signed-off-by: Koni Marti <koni.marti@gmail.com> Tested-by: Jens Grassel <jens@wegtam.com> Reviewed-by: Tim Culverhouse <tim@timculverhouse.com> Acked-by: Robin Jarry <robin@jarry.cc>
Diffstat (limited to 'lib')
-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
+}