diff options
author | Koni Marti <koni.marti@gmail.com> | 2024-06-14 23:06:56 +0200 |
---|---|---|
committer | Robin Jarry <robin@jarry.cc> | 2024-08-20 11:54:34 +0200 |
commit | 108a8ca1d2728dc7b4258fb455b78fab1f6a063d (patch) | |
tree | 16f442d07d246bad0ab30b14ed14aea7ac188086 /lib | |
parent | 7558ccab40dabc44e810342534cdcd0ca20929a1 (diff) | |
download | aerc-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.go | 69 |
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 +} |